diff options
author | shadchin <shadchin@yandex-team.com> | 2024-02-12 07:53:52 +0300 |
---|---|---|
committer | shadchin <shadchin@yandex-team.com> | 2024-02-12 08:07:36 +0300 |
commit | ce1b7ca3171f9158180640c6a02a74b4afffedea (patch) | |
tree | e47c1e8391b1b0128262c1e9b1e6ed4c8fff2348 /contrib/tools/python3/src/Modules/itertoolsmodule.c | |
parent | 57350d96f030db90f220ce50ee591d5c5d403df7 (diff) | |
download | ydb-ce1b7ca3171f9158180640c6a02a74b4afffedea.tar.gz |
Update Python from 3.11.8 to 3.12.2
Diffstat (limited to 'contrib/tools/python3/src/Modules/itertoolsmodule.c')
-rw-r--r-- | contrib/tools/python3/src/Modules/itertoolsmodule.c | 2069 |
1 files changed, 964 insertions, 1105 deletions
diff --git a/contrib/tools/python3/src/Modules/itertoolsmodule.c b/contrib/tools/python3/src/Modules/itertoolsmodule.c index 7a02a0d25b..24e77c485d 100644 --- a/contrib/tools/python3/src/Modules/itertoolsmodule.c +++ b/contrib/tools/python3/src/Modules/itertoolsmodule.c @@ -2,54 +2,262 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_long.h" // _PyLong_GetZero() +#include "pycore_moduleobject.h" // _PyModule_GetState() +#include "pycore_typeobject.h" // _PyType_GetModuleState() #include "pycore_object.h" // _PyObject_GC_TRACK() #include "pycore_tuple.h" // _PyTuple_ITEMS() +#include "structmember.h" // PyMemberDef #include <stddef.h> // offsetof() /* Itertools module written and maintained by Raymond D. Hettinger <python@rcn.com> */ +typedef struct { + PyTypeObject *accumulate_type; + PyTypeObject *batched_type; + PyTypeObject *chain_type; + PyTypeObject *combinations_type; + PyTypeObject *compress_type; + PyTypeObject *count_type; + PyTypeObject *cwr_type; + PyTypeObject *cycle_type; + PyTypeObject *dropwhile_type; + PyTypeObject *filterfalse_type; + PyTypeObject *groupby_type; + PyTypeObject *_grouper_type; + PyTypeObject *islice_type; + PyTypeObject *pairwise_type; + PyTypeObject *permutations_type; + PyTypeObject *product_type; + PyTypeObject *repeat_type; + PyTypeObject *starmap_type; + PyTypeObject *takewhile_type; + PyTypeObject *tee_type; + PyTypeObject *teedataobject_type; + PyTypeObject *ziplongest_type; +} itertools_state; + +static inline itertools_state * +get_module_state(PyObject *mod) +{ + void *state = _PyModule_GetState(mod); + assert(state != NULL); + return (itertools_state *)state; +} + +static inline itertools_state * +get_module_state_by_cls(PyTypeObject *cls) +{ + void *state = _PyType_GetModuleState(cls); + assert(state != NULL); + return (itertools_state *)state; +} + +static struct PyModuleDef itertoolsmodule; + +static inline itertools_state * +find_state_by_type(PyTypeObject *tp) +{ + PyObject *mod = PyType_GetModuleByDef(tp, &itertoolsmodule); + assert(mod != NULL); + return get_module_state(mod); +} + /*[clinic input] module itertools -class itertools.groupby "groupbyobject *" "&groupby_type" -class itertools._grouper "_grouperobject *" "&_grouper_type" -class itertools.teedataobject "teedataobject *" "&teedataobject_type" -class itertools._tee "teeobject *" "&tee_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.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.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" +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 *" "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" +class itertools.starmap "starmapobject *" "clinic_state()->starmap_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" +class itertools.accumulate "accumulateobject *" "clinic_state()->accumulate_type" +class itertools.compress "compressobject *" "clinic_state()->compress_type" +class itertools.filterfalse "filterfalseobject *" "clinic_state()->filterfalse_type" +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=6498ed21fbe1bf94]*/ - -static PyTypeObject groupby_type; -static PyTypeObject _grouper_type; -static PyTypeObject teedataobject_type; -static PyTypeObject tee_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; -static PyTypeObject count_type; -static PyTypeObject pairwise_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)) #include "clinic/itertoolsmodule.c.h" +#undef clinic_state_by_cls +#undef clinic_state + +/* Deprecation of pickle support: GH-101588 *********************************/ + +#define ITERTOOL_PICKLE_DEPRECATION \ + if (PyErr_WarnEx( \ + PyExc_DeprecationWarning, \ + "Pickle, copy, and deepcopy support will be " \ + "removed from itertools in Python 3.14.", 1) < 0) { \ + return NULL; \ + } + +/* batched object ************************************************************/ + +/* Note: The built-in zip() function includes a "strict" argument + that was needed because that function would silently truncate data, + and there was no easy way for a user to detect the data loss. + The same reasoning does not apply to batched() which never drops data. + Instead, batched() produces a shorter tuple which can be handled + as the user sees fit. If requested, it would be reasonable to add + "fillvalue" support which had demonstrated value in zip_longest(). + For now, the API is kept simple and clean. + */ + +typedef struct { + PyObject_HEAD + PyObject *it; + Py_ssize_t batch_size; +} batchedobject; + +/*[clinic input] +@classmethod +itertools.batched.__new__ as batched_new + iterable: object + n: Py_ssize_t +Batch data into tuples of length n. The last batch may be shorter than n. + +Loops over the input iterable and accumulates data into tuples +up to size n. The input is consumed lazily, just enough to +fill a batch. The result is yielded as soon as a batch is full +or when the input iterable is exhausted. + + >>> for batch in batched('ABCDEFG', 3): + ... print(batch) + ... + ('A', 'B', 'C') + ('D', 'E', 'F') + ('G',) + +[clinic start generated code]*/ + +static PyObject * +batched_new_impl(PyTypeObject *type, PyObject *iterable, Py_ssize_t n) +/*[clinic end generated code: output=7ebc954d655371b6 input=ffd70726927c5129]*/ +{ + PyObject *it; + batchedobject *bo; + + if (n < 1) { + /* We could define the n==0 case to return an empty iterator + but that is at odds with the idea that batching should + never throw-away input data. + */ + PyErr_SetString(PyExc_ValueError, "n must be at least one"); + return NULL; + } + it = PyObject_GetIter(iterable); + if (it == NULL) { + return NULL; + } + + /* create batchedobject structure */ + bo = (batchedobject *)type->tp_alloc(type, 0); + if (bo == NULL) { + Py_DECREF(it); + return NULL; + } + bo->batch_size = n; + bo->it = it; + return (PyObject *)bo; +} + +static void +batched_dealloc(batchedobject *bo) +{ + PyTypeObject *tp = Py_TYPE(bo); + PyObject_GC_UnTrack(bo); + Py_XDECREF(bo->it); + tp->tp_free(bo); + Py_DECREF(tp); +} + +static int +batched_traverse(batchedobject *bo, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(bo)); + Py_VISIT(bo->it); + return 0; +} + +static PyObject * +batched_next(batchedobject *bo) +{ + Py_ssize_t i; + Py_ssize_t n = bo->batch_size; + PyObject *it = bo->it; + PyObject *item; + PyObject *result; + + if (it == NULL) { + return NULL; + } + result = PyTuple_New(n); + if (result == NULL) { + return NULL; + } + iternextfunc iternext = *Py_TYPE(it)->tp_iternext; + PyObject **items = _PyTuple_ITEMS(result); + for (i=0 ; i < n ; i++) { + item = iternext(it); + if (item == NULL) { + goto null_item; + } + items[i] = item; + } + return result; + + null_item: + if (PyErr_Occurred()) { + if (!PyErr_ExceptionMatches(PyExc_StopIteration)) { + /* Input raised an exception other than StopIteration */ + Py_CLEAR(bo->it); + Py_DECREF(result); + return NULL; + } + PyErr_Clear(); + } + if (i == 0) { + Py_CLEAR(bo->it); + Py_DECREF(result); + return NULL; + } + _PyTuple_Resize(&result, i); + return result; +} + +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, +}; + /* pairwise object ***********************************************************/ @@ -94,15 +302,18 @@ pairwise_new_impl(PyTypeObject *type, PyObject *iterable) static void pairwise_dealloc(pairwiseobject *po) { + PyTypeObject *tp = Py_TYPE(po); PyObject_GC_UnTrack(po); Py_XDECREF(po->it); Py_XDECREF(po->old); - Py_TYPE(po)->tp_free(po); + tp->tp_free(po); + Py_DECREF(tp); } static int pairwise_traverse(pairwiseobject *po, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(po)); Py_VISIT(po->it); Py_VISIT(po->old); return 0; @@ -146,48 +357,25 @@ pairwise_next(pairwiseobject *po) return result; } -static PyTypeObject pairwise_type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "itertools.pairwise", /* tp_name */ - sizeof(pairwiseobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)pairwise_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 */ - pairwise_new__doc__, /* tp_doc */ - (traverseproc)pairwise_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)pairwise_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 */ - pairwise_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot pairwise_slots[] = { + {Py_tp_dealloc, pairwise_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)pairwise_new__doc__}, + {Py_tp_traverse, pairwise_traverse}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, pairwise_next}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, pairwise_new}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec pairwise_spec = { + .name = "itertools.pairwise", + .basicsize = sizeof(pairwiseobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = pairwise_slots, }; @@ -201,6 +389,7 @@ typedef struct { PyObject *currkey; PyObject *currvalue; const void *currgrouper; /* borrowed reference */ + itertools_state *state; } groupbyobject; static PyObject *_grouper_create(groupbyobject *, PyObject *); @@ -231,31 +420,34 @@ itertools_groupby_impl(PyTypeObject *type, PyObject *it, PyObject *keyfunc) gbo->tgtkey = NULL; gbo->currkey = NULL; gbo->currvalue = NULL; - gbo->keyfunc = keyfunc; - Py_INCREF(keyfunc); + gbo->keyfunc = Py_NewRef(keyfunc); gbo->it = PyObject_GetIter(it); if (gbo->it == NULL) { Py_DECREF(gbo); return NULL; } + gbo->state = find_state_by_type(type); return (PyObject *)gbo; } 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); - Py_TYPE(gbo)->tp_free(gbo); + tp->tp_free(gbo); + Py_DECREF(tp); } static int groupby_traverse(groupbyobject *gbo, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(gbo)); Py_VISIT(gbo->it); Py_VISIT(gbo->keyfunc); Py_VISIT(gbo->tgtkey); @@ -274,8 +466,7 @@ groupby_step(groupbyobject *gbo) return -1; if (gbo->keyfunc == Py_None) { - newkey = newvalue; - Py_INCREF(newvalue); + newkey = Py_NewRef(newvalue); } else { newkey = PyObject_CallOneArg(gbo->keyfunc, newvalue); if (newkey == NULL) { @@ -334,6 +525,7 @@ groupby_reduce(groupbyobject *lz, PyObject *Py_UNUSED(ignored)) /* reduce as a 'new' call with an optional 'setstate' if groupby * has started */ + ITERTOOL_PICKLE_DEPRECATION; PyObject *value; if (lz->tgtkey && lz->currkey && lz->currvalue) value = Py_BuildValue("O(OO)(OOO)", Py_TYPE(lz), @@ -350,6 +542,7 @@ PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); static PyObject * groupby_setstate(groupbyobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; PyObject *currkey, *currvalue, *tgtkey; if (!PyTuple_Check(state)) { PyErr_SetString(PyExc_TypeError, "state is not a tuple"); @@ -377,50 +570,26 @@ static PyMethodDef groupby_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyTypeObject groupby_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "itertools.groupby", /* tp_name */ - sizeof(groupbyobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)groupby_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_groupby__doc__, /* tp_doc */ - (traverseproc)groupby_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)groupby_next, /* tp_iternext */ - groupby_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_groupby, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot groupby_slots[] = { + {Py_tp_dealloc, groupby_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)itertools_groupby__doc__}, + {Py_tp_traverse, groupby_traverse}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, groupby_next}, + {Py_tp_methods, groupby_methods}, + {Py_tp_new, itertools_groupby}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, }; +static PyType_Spec groupby_spec = { + .name = "itertools.groupby", + .basicsize= sizeof(groupbyobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = groupby_slots, +}; /* _grouper object (internal) ************************************************/ @@ -434,7 +603,7 @@ typedef struct { @classmethod itertools._grouper.__new__ - parent: object(subclass_of='&groupby_type') + parent: object(subclass_of='clinic_state_by_cls()->groupby_type') tgtkey: object / [clinic start generated code]*/ @@ -442,7 +611,7 @@ itertools._grouper.__new__ static PyObject * itertools__grouper_impl(PyTypeObject *type, PyObject *parent, PyObject *tgtkey) -/*[clinic end generated code: output=462efb1cdebb5914 input=dc180d7771fc8c59]*/ +/*[clinic end generated code: output=462efb1cdebb5914 input=afe05eb477118f12]*/ { return _grouper_create((groupbyobject*) parent, tgtkey); } @@ -450,15 +619,12 @@ itertools__grouper_impl(PyTypeObject *type, PyObject *parent, static PyObject * _grouper_create(groupbyobject *parent, PyObject *tgtkey) { - _grouperobject *igo; - - igo = PyObject_GC_New(_grouperobject, &_grouper_type); + itertools_state *state = parent->state; + _grouperobject *igo = PyObject_GC_New(_grouperobject, state->_grouper_type); if (igo == NULL) return NULL; - igo->parent = (PyObject *)parent; - Py_INCREF(parent); - igo->tgtkey = tgtkey; - Py_INCREF(tgtkey); + igo->parent = Py_NewRef(parent); + igo->tgtkey = Py_NewRef(tgtkey); parent->currgrouper = igo; /* borrowed reference */ PyObject_GC_Track(igo); @@ -468,15 +634,18 @@ _grouper_create(groupbyobject *parent, PyObject *tgtkey) static void _grouper_dealloc(_grouperobject *igo) { + PyTypeObject *tp = Py_TYPE(igo); PyObject_GC_UnTrack(igo); Py_DECREF(igo->parent); Py_DECREF(igo->tgtkey); PyObject_GC_Del(igo); + Py_DECREF(tp); } static int _grouper_traverse(_grouperobject *igo, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(igo)); Py_VISIT(igo->parent); Py_VISIT(igo->tgtkey); return 0; @@ -512,6 +681,7 @@ _grouper_next(_grouperobject *igo) static PyObject * _grouper_reduce(_grouperobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; if (((groupbyobject *)lz->parent)->currgrouper != lz) { return Py_BuildValue("N(())", _PyEval_GetBuiltin(&_Py_ID(iter))); } @@ -524,48 +694,24 @@ static PyMethodDef _grouper_methods[] = { {NULL, NULL} /* sentinel */ }; +static PyType_Slot _grouper_slots[] = { + {Py_tp_dealloc, _grouper_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_traverse, _grouper_traverse}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, _grouper_next}, + {Py_tp_methods, _grouper_methods}, + {Py_tp_new, itertools__grouper}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; -static PyTypeObject _grouper_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "itertools._grouper", /* tp_name */ - sizeof(_grouperobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)_grouper_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 */ - 0, /* tp_doc */ - (traverseproc)_grouper_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)_grouper_next, /* tp_iternext */ - _grouper_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__grouper, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Spec _grouper_spec = { + .name = "itertools._grouper", + .basicsize = sizeof(_grouperobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = _grouper_slots, }; @@ -595,33 +741,32 @@ typedef struct { teedataobject *dataobj; int index; /* 0 <= index <= LINKCELLS */ PyObject *weakreflist; + itertools_state *state; } teeobject; static PyObject * -teedataobject_newinternal(PyObject *it) +teedataobject_newinternal(itertools_state *state, PyObject *it) { teedataobject *tdo; - tdo = PyObject_GC_New(teedataobject, &teedataobject_type); + tdo = PyObject_GC_New(teedataobject, state->teedataobject_type); if (tdo == NULL) return NULL; tdo->running = 0; tdo->numread = 0; tdo->nextlink = NULL; - Py_INCREF(it); - tdo->it = it; + tdo->it = Py_NewRef(it); PyObject_GC_Track(tdo); return (PyObject *)tdo; } static PyObject * -teedataobject_jumplink(teedataobject *tdo) +teedataobject_jumplink(itertools_state *state, teedataobject *tdo) { if (tdo->nextlink == NULL) - tdo->nextlink = teedataobject_newinternal(tdo->it); - Py_XINCREF(tdo->nextlink); - return tdo->nextlink; + tdo->nextlink = teedataobject_newinternal(state, tdo->it); + return Py_XNewRef(tdo->nextlink); } static PyObject * @@ -648,8 +793,7 @@ teedataobject_getitem(teedataobject *tdo, int i) tdo->numread++; tdo->values[i] = value; } - Py_INCREF(value); - return value; + return Py_NewRef(value); } static int @@ -657,6 +801,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]); @@ -665,14 +810,13 @@ 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; - Py_DECREF(obj); - obj = nextlink; + Py_SETREF(obj, nextlink); } Py_XDECREF(obj); } @@ -688,21 +832,25 @@ teedataobject_clear(teedataobject *tdo) Py_CLEAR(tdo->values[i]); tmp = tdo->nextlink; tdo->nextlink = NULL; - teedataobject_safe_decref(tmp); + itertools_state *state = get_module_state_by_cls(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 * teedataobject_reduce(teedataobject *tdo, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; int i; /* create a temporary list of already iterated values */ PyObject *values = PyList_New(tdo->numread); @@ -736,9 +884,10 @@ itertools_teedataobject_impl(PyTypeObject *type, PyObject *it, teedataobject *tdo; Py_ssize_t i, len; - assert(type == &teedataobject_type); + itertools_state *state = get_module_state_by_cls(type); + assert(type == state->teedataobject_type); - tdo = (teedataobject *)teedataobject_newinternal(it); + tdo = (teedataobject *)teedataobject_newinternal(state, it); if (!tdo) return NULL; @@ -754,11 +903,10 @@ 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); - Py_INCREF(next); - tdo->nextlink = next; + tdo->nextlink = Py_NewRef(next); } } else { if (next != Py_None) @@ -778,47 +926,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, }; @@ -828,7 +953,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); @@ -844,6 +969,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; } @@ -853,13 +979,13 @@ tee_copy(teeobject *to, PyObject *Py_UNUSED(ignored)) { teeobject *newto; - newto = PyObject_GC_New(teeobject, &tee_type); + newto = PyObject_GC_New(teeobject, Py_TYPE(to)); if (newto == NULL) return NULL; - Py_INCREF(to->dataobj); - newto->dataobj = to->dataobj; + 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; } @@ -867,7 +993,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; @@ -875,17 +1001,17 @@ 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; } - PyObject *dataobj = teedataobject_newinternal(it); + PyObject *dataobj = teedataobject_newinternal(state, it); if (!dataobj) { 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; @@ -893,6 +1019,7 @@ tee_fromiterable(PyObject *iterable) to->dataobj = (teedataobject *)dataobj; to->index = 0; to->weakreflist = NULL; + to->state = state; PyObject_GC_Track(to); done: Py_DECREF(it); @@ -911,7 +1038,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 = get_module_state_by_cls(type); + return tee_fromiterable(state, iterable); } static int @@ -926,27 +1054,32 @@ 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 * tee_reduce(teeobject *to, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; return Py_BuildValue("O(())(Oi)", Py_TYPE(to), to->dataobj, to->index); } static PyObject * tee_setstate(teeobject *to, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; teedataobject *tdo; int index; if (!PyTuple_Check(state)) { PyErr_SetString(PyExc_TypeError, "state is not a tuple"); return NULL; } - if (!PyArg_ParseTuple(state, "O!i", &teedataobject_type, &tdo, &index)) { + PyTypeObject *tdo_type = to->state->teedataobject_type; + if (!PyArg_ParseTuple(state, "O!i", tdo_type, &tdo, &index)) { return NULL; } if (index < 0 || index > LINKCELLS) { @@ -966,47 +1099,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] @@ -1048,7 +1165,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); @@ -1132,15 +1250,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; @@ -1173,13 +1294,13 @@ cycle_next(cycleobject *lz) lz->index++; if (lz->index >= PyList_GET_SIZE(lz->saved)) lz->index = 0; - Py_INCREF(item); - return item; + return Py_NewRef(item); } static PyObject * cycle_reduce(cycleobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; /* Create a new cycle with the iterator tuple, then set the saved state */ if (lz->it == NULL) { PyObject *it = PyObject_GetIter(lz->saved); @@ -1203,6 +1324,7 @@ cycle_reduce(cycleobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * cycle_setstate(cycleobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; PyObject *saved=NULL; int firstpass; if (!PyTuple_Check(state)) { @@ -1228,48 +1350,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, }; @@ -1311,8 +1410,7 @@ itertools_dropwhile_impl(PyTypeObject *type, PyObject *func, PyObject *seq) Py_DECREF(it); return NULL; } - Py_INCREF(func); - lz->func = func; + lz->func = Py_NewRef(func); lz->it = it; lz->start = 0; @@ -1322,15 +1420,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; @@ -1372,12 +1473,14 @@ dropwhile_next(dropwhileobject *lz) static PyObject * dropwhile_reduce(dropwhileobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; return Py_BuildValue("O(OO)l", Py_TYPE(lz), lz->func, lz->it, lz->start); } static PyObject * dropwhile_setstate(dropwhileobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; int start = PyObject_IsTrue(state); if (start < 0) return NULL; @@ -1393,48 +1496,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, }; @@ -1474,8 +1554,7 @@ itertools_takewhile_impl(PyTypeObject *type, PyObject *func, PyObject *seq) Py_DECREF(it); return NULL; } - Py_INCREF(func); - lz->func = func; + lz->func = Py_NewRef(func); lz->it = it; lz->stop = 0; @@ -1485,15 +1564,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; @@ -1531,12 +1613,14 @@ takewhile_next(takewhileobject *lz) static PyObject * takewhile_reduce(takewhileobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; return Py_BuildValue("O(OO)l", Py_TYPE(lz), lz->func, lz->it, lz->stop); } static PyObject * takewhile_reduce_setstate(takewhileobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; int stop = PyObject_IsTrue(state); if (stop < 0) @@ -1553,48 +1637,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, }; @@ -1609,8 +1670,6 @@ typedef struct { Py_ssize_t cnt; } isliceobject; -static PyTypeObject islice_type; - static PyObject * islice_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { @@ -1620,7 +1679,9 @@ 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) && + itertools_state *st = find_state_by_type(type); + PyTypeObject *islice_type = st->islice_type; + if ((type == islice_type || type->tp_init == islice_type->tp_init) && !_PyArg_NoKeywords("islice", kwds)) return NULL; @@ -1699,14 +1760,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; } @@ -1753,6 +1817,7 @@ empty: static PyObject * islice_reduce(isliceobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; /* When unpickled, generate a new object with the same bounds, * then 'setstate' with the next and count */ @@ -1771,8 +1836,7 @@ islice_reduce(isliceobject *lz, PyObject *Py_UNUSED(ignored)) return Py_BuildValue("O(Nn)n", Py_TYPE(lz), empty_it, 0, 0); } if (lz->stop == -1) { - stop = Py_None; - Py_INCREF(stop); + stop = Py_NewRef(Py_None); } else { stop = PyLong_FromSsize_t(lz->stop); if (stop == NULL) @@ -1786,6 +1850,7 @@ islice_reduce(isliceobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * islice_setstate(isliceobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; Py_ssize_t cnt = PyLong_AsSsize_t(state); if (cnt == -1 && PyErr_Occurred()) @@ -1813,48 +1878,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, }; @@ -1893,8 +1935,7 @@ itertools_starmap_impl(PyTypeObject *type, PyObject *func, PyObject *seq) Py_DECREF(it); return NULL; } - Py_INCREF(func); - lz->func = func; + lz->func = Py_NewRef(func); lz->it = it; return (PyObject *)lz; @@ -1903,15 +1944,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; @@ -1942,6 +1986,7 @@ starmap_next(starmapobject *lz) static PyObject * starmap_reduce(starmapobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; /* Just pickle the iterator */ return Py_BuildValue("O(OO)", Py_TYPE(lz), lz->func, lz->it); } @@ -1952,48 +1997,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, }; @@ -2005,8 +2027,6 @@ typedef struct { PyObject *active; /* Currently running input iterator */ } chainobject; -static PyTypeObject chain_type; - static PyObject * chain_new_internal(PyTypeObject *type, PyObject *source) { @@ -2028,7 +2048,9 @@ chain_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *source; - if ((type == &chain_type || type->tp_init == chain_type.tp_init) && + 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; @@ -2063,15 +2085,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; @@ -2118,6 +2143,7 @@ chain_next(chainobject *lz) static PyObject * chain_reduce(chainobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; if (lz->source) { /* we can't pickle function objects (itertools.from_iterable) so * we must use setstate to replace the iterable. One day we @@ -2137,6 +2163,7 @@ chain_reduce(chainobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * chain_setstate(chainobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; PyObject *source, *active=NULL; if (!PyTuple_Check(state)) { @@ -2176,48 +2203,25 @@ 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 | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = chain_slots, }; @@ -2231,8 +2235,6 @@ typedef struct { int stopped; /* set to 1 when the iterator is exhausted */ } productobject; -static PyTypeObject product_type; - static PyObject * product_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { @@ -2319,22 +2321,22 @@ error: 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); - Py_TYPE(lz)->tp_free(lz); + tp->tp_free(lz); + Py_DECREF(tp); } static PyObject * product_sizeof(productobject *lz, void *unused) { - Py_ssize_t res; - - res = _PyObject_SIZE(Py_TYPE(lz)); - res += PyTuple_GET_SIZE(lz->pools) * sizeof(Py_ssize_t); - return PyLong_FromSsize_t(res); + size_t res = _PyObject_SIZE(Py_TYPE(lz)); + res += (size_t)PyTuple_GET_SIZE(lz->pools) * sizeof(Py_ssize_t); + return PyLong_FromSize_t(res); } PyDoc_STRVAR(sizeof_doc, "Returns size in memory, in bytes."); @@ -2342,6 +2344,7 @@ PyDoc_STRVAR(sizeof_doc, "Returns size in memory, in bytes."); static int product_traverse(productobject *lz, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(lz)); Py_VISIT(lz->pools); Py_VISIT(lz->result); return 0; @@ -2426,8 +2429,7 @@ product_next(productobject *lz) goto empty; } - Py_INCREF(result); - return result; + return Py_NewRef(result); empty: lz->stopped = 1; @@ -2437,6 +2439,7 @@ empty: static PyObject * product_reduce(productobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; if (lz->stopped) { return Py_BuildValue("O(())", Py_TYPE(lz)); } else if (lz->result == NULL) { @@ -2467,6 +2470,7 @@ product_reduce(productobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * product_setstate(productobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; PyObject *result; Py_ssize_t n, i; @@ -2534,48 +2538,25 @@ product(A, repeat=4) means the same as product(A, A, A, A).\n\n\ product('ab', range(3)) --> ('a',0) ('a',1) ('a',2) ('b',0) ('b',1) ('b',2)\n\ product((0,1), (0,1), (0,1)) --> (0,0,0) (0,0,1) (0,1,0) (0,1,1) (1,0,0) ..."); -static PyTypeObject product_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "itertools.product", /* tp_name */ - sizeof(productobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)product_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 */ - product_doc, /* tp_doc */ - (traverseproc)product_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)product_next, /* tp_iternext */ - product_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 */ - product_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot product_slots[] = { + {Py_tp_dealloc, product_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)product_doc}, + {Py_tp_traverse, product_traverse}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, product_next}, + {Py_tp_methods, product_methods}, + {Py_tp_new, product_new}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec product_spec = { + .name = "itertools.product", + .basicsize = sizeof(productobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = product_slots, }; @@ -2653,27 +2634,28 @@ 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 * combinations_sizeof(combinationsobject *co, void *unused) { - Py_ssize_t res; - - res = _PyObject_SIZE(Py_TYPE(co)); - res += co->r * sizeof(Py_ssize_t); - return PyLong_FromSsize_t(res); + size_t res = _PyObject_SIZE(Py_TYPE(co)); + res += (size_t)co->r * sizeof(Py_ssize_t); + return PyLong_FromSize_t(res); } 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; @@ -2757,8 +2739,7 @@ combinations_next(combinationsobject *co) } } - Py_INCREF(result); - return result; + return Py_NewRef(result); empty: co->stopped = 1; @@ -2768,6 +2749,7 @@ empty: static PyObject * combinations_reduce(combinationsobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; if (lz->result == NULL) { return Py_BuildValue("O(On)", Py_TYPE(lz), lz->pool, lz->r); } else if (lz->stopped) { @@ -2797,6 +2779,7 @@ combinations_reduce(combinationsobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * combinations_setstate(combinationsobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; PyObject *result; Py_ssize_t i; Py_ssize_t n = PyTuple_GET_SIZE(lz->pool); @@ -2845,48 +2828,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, }; @@ -2990,27 +2950,28 @@ 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 * cwr_sizeof(cwrobject *co, void *unused) { - Py_ssize_t res; - - res = _PyObject_SIZE(Py_TYPE(co)); - res += co->r * sizeof(Py_ssize_t); - return PyLong_FromSsize_t(res); + size_t res = _PyObject_SIZE(Py_TYPE(co)); + res += (size_t)co->r * sizeof(Py_ssize_t); + return PyLong_FromSize_t(res); } 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; @@ -3088,8 +3049,7 @@ cwr_next(cwrobject *co) } } - Py_INCREF(result); - return result; + return Py_NewRef(result); empty: co->stopped = 1; @@ -3099,6 +3059,7 @@ empty: static PyObject * cwr_reduce(cwrobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; if (lz->result == NULL) { return Py_BuildValue("O(On)", Py_TYPE(lz), lz->pool, lz->r); } else if (lz->stopped) { @@ -3127,6 +3088,7 @@ cwr_reduce(cwrobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * cwr_setstate(cwrobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; PyObject *result; Py_ssize_t n, i; @@ -3172,48 +3134,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, }; @@ -3336,28 +3275,29 @@ 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 * permutations_sizeof(permutationsobject *po, void *unused) { - Py_ssize_t res; - - res = _PyObject_SIZE(Py_TYPE(po)); - res += PyTuple_GET_SIZE(po->pool) * sizeof(Py_ssize_t); - res += po->r * sizeof(Py_ssize_t); - return PyLong_FromSsize_t(res); + size_t res = _PyObject_SIZE(Py_TYPE(po)); + res += (size_t)PyTuple_GET_SIZE(po->pool) * sizeof(Py_ssize_t); + res += (size_t)po->r * sizeof(Py_ssize_t); + return PyLong_FromSize_t(res); } 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; @@ -3446,8 +3386,7 @@ permutations_next(permutationsobject *po) if (i < 0) goto empty; } - Py_INCREF(result); - return result; + return Py_NewRef(result); empty: po->stopped = 1; @@ -3457,6 +3396,7 @@ empty: static PyObject * permutations_reduce(permutationsobject *po, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; if (po->result == NULL) { return Py_BuildValue("O(On)", Py_TYPE(po), po->pool, po->r); } else if (po->stopped) { @@ -3499,6 +3439,7 @@ permutations_reduce(permutationsobject *po, PyObject *Py_UNUSED(ignored)) static PyObject * permutations_setstate(permutationsobject *po, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; PyObject *indices, *cycles, *result; Py_ssize_t n, i; @@ -3564,48 +3505,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, }; @@ -3617,6 +3535,7 @@ typedef struct { PyObject *it; PyObject *binop; PyObject *initial; + itertools_state *state; } accumulateobject; /*[clinic input] @@ -3650,30 +3569,32 @@ itertools_accumulate_impl(PyTypeObject *type, PyObject *iterable, } if (binop != Py_None) { - Py_XINCREF(binop); - lz->binop = binop; + lz->binop = Py_XNewRef(binop); } lz->total = NULL; lz->it = it; - Py_XINCREF(initial); - lz->initial = initial; + lz->initial = Py_XNewRef(initial); + lz->state = find_state_by_type(type); return (PyObject *)lz; } 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); - Py_TYPE(lz)->tp_free(lz); + tp->tp_free(lz); + Py_DECREF(tp); } static int accumulate_traverse(accumulateobject *lz, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(lz)); Py_VISIT(lz->binop); Py_VISIT(lz->it); Py_VISIT(lz->total); @@ -3688,18 +3609,15 @@ accumulate_next(accumulateobject *lz) if (lz->initial != Py_None) { lz->total = lz->initial; - Py_INCREF(Py_None); - lz->initial = Py_None; - Py_INCREF(lz->total); - return lz->total; + lz->initial = Py_NewRef(Py_None); + return Py_NewRef(lz->total); } val = (*Py_TYPE(lz->it)->tp_iternext)(lz->it); if (val == NULL) return NULL; if (lz->total == NULL) { - Py_INCREF(val); - lz->total = val; + lz->total = Py_NewRef(val); return lz->total; } @@ -3719,13 +3637,14 @@ accumulate_next(accumulateobject *lz) static PyObject * accumulate_reduce(accumulateobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; + itertools_state *state = lz->state; + 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; @@ -3735,11 +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; - if (PyType_Ready(&islice_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; @@ -3747,7 +3662,8 @@ 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); + + 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, @@ -3757,6 +3673,7 @@ accumulate_reduce(accumulateobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * accumulate_setstate(accumulateobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; Py_INCREF(state); Py_XSETREF(lz->total, state); Py_RETURN_NONE; @@ -3770,48 +3687,25 @@ static PyMethodDef accumulate_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyTypeObject accumulate_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "itertools.accumulate", /* tp_name */ - sizeof(accumulateobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)accumulate_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_accumulate__doc__, /* tp_doc */ - (traverseproc)accumulate_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)accumulate_next, /* tp_iternext */ - accumulate_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_accumulate, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot accumulate_slots[] = { + {Py_tp_dealloc, accumulate_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)itertools_accumulate__doc__}, + {Py_tp_traverse, accumulate_traverse}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, accumulate_next}, + {Py_tp_methods, accumulate_methods}, + {Py_tp_new, itertools_accumulate}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec accumulate_spec = { + .name = "itertools.accumulate", + .basicsize = sizeof(accumulateobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = accumulate_slots, }; @@ -3872,15 +3766,18 @@ fail: static void compress_dealloc(compressobject *lz) { + PyTypeObject *tp = Py_TYPE(lz); PyObject_GC_UnTrack(lz); Py_XDECREF(lz->data); Py_XDECREF(lz->selectors); - Py_TYPE(lz)->tp_free(lz); + tp->tp_free(lz); + Py_DECREF(tp); } static int compress_traverse(compressobject *lz, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(lz)); Py_VISIT(lz->data); Py_VISIT(lz->selectors); return 0; @@ -3925,6 +3822,7 @@ compress_next(compressobject *lz) static PyObject * compress_reduce(compressobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; return Py_BuildValue("O(OO)", Py_TYPE(lz), lz->data, lz->selectors); } @@ -3935,48 +3833,25 @@ static PyMethodDef compress_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyTypeObject compress_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "itertools.compress", /* tp_name */ - sizeof(compressobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)compress_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_compress__doc__, /* tp_doc */ - (traverseproc)compress_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)compress_next, /* tp_iternext */ - compress_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_compress, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot compress_slots[] = { + {Py_tp_dealloc, compress_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)itertools_compress__doc__}, + {Py_tp_traverse, compress_traverse}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, compress_next}, + {Py_tp_methods, compress_methods}, + {Py_tp_new, itertools_compress}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec compress_spec = { + .name = "itertools.compress", + .basicsize = sizeof(compressobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = compress_slots, }; @@ -4017,8 +3892,7 @@ itertools_filterfalse_impl(PyTypeObject *type, PyObject *func, PyObject *seq) Py_DECREF(it); return NULL; } - Py_INCREF(func); - lz->func = func; + lz->func = Py_NewRef(func); lz->it = it; return (PyObject *)lz; @@ -4027,15 +3901,18 @@ itertools_filterfalse_impl(PyTypeObject *type, PyObject *func, PyObject *seq) static void filterfalse_dealloc(filterfalseobject *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 filterfalse_traverse(filterfalseobject *lz, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(lz)); Py_VISIT(lz->it); Py_VISIT(lz->func); return 0; @@ -4078,6 +3955,7 @@ filterfalse_next(filterfalseobject *lz) static PyObject * filterfalse_reduce(filterfalseobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; return Py_BuildValue("O(OO)", Py_TYPE(lz), lz->func, lz->it); } @@ -4087,48 +3965,25 @@ static PyMethodDef filterfalse_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyTypeObject filterfalse_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "itertools.filterfalse", /* tp_name */ - sizeof(filterfalseobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)filterfalse_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_filterfalse__doc__, /* tp_doc */ - (traverseproc)filterfalse_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)filterfalse_next, /* tp_iternext */ - filterfalse_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_filterfalse, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot filterfalse_slots[] = { + {Py_tp_dealloc, filterfalse_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)itertools_filterfalse__doc__}, + {Py_tp_traverse, filterfalse_traverse}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, filterfalse_next}, + {Py_tp_methods, filterfalse_methods}, + {Py_tp_new, itertools_filterfalse}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec filterfalse_spec = { + .name = "itertools.filterfalse", + .basicsize = sizeof(filterfalseobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = filterfalse_slots, }; @@ -4254,15 +4109,18 @@ itertools_count_impl(PyTypeObject *type, PyObject *long_cnt, 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); - Py_TYPE(lz)->tp_free(lz); + tp->tp_free(lz); + Py_DECREF(tp); } static int count_traverse(countobject *lz, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(lz)); Py_VISIT(lz->long_cnt); Py_VISIT(lz->long_step); return 0; @@ -4325,6 +4183,7 @@ count_repr(countobject *lz) static PyObject * count_reduce(countobject *lz, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; if (lz->cnt == PY_SSIZE_T_MAX) return Py_BuildValue("O(OO)", Py_TYPE(lz), lz->long_cnt, lz->long_step); return Py_BuildValue("O(n)", Py_TYPE(lz), lz->cnt); @@ -4336,48 +4195,26 @@ static PyMethodDef count_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyTypeObject count_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "itertools.count", /* tp_name */ - sizeof(countobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)count_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc)count_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 */ - itertools_count__doc__, /* tp_doc */ - (traverseproc)count_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)count_next, /* tp_iternext */ - count_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_count, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot count_slots[] = { + {Py_tp_dealloc, count_dealloc}, + {Py_tp_repr, count_repr}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)itertools_count__doc__}, + {Py_tp_traverse, count_traverse}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, count_next}, + {Py_tp_methods, count_methods}, + {Py_tp_new, itertools_count}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec count_spec = { + .name = "itertools.count", + .basicsize = sizeof(countobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = count_slots, }; @@ -4389,8 +4226,6 @@ typedef struct { Py_ssize_t cnt; } repeatobject; -static PyTypeObject repeat_type; - static PyObject * repeat_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { @@ -4412,8 +4247,7 @@ repeat_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ro = (repeatobject *)type->tp_alloc(type, 0); if (ro == NULL) return NULL; - Py_INCREF(element); - ro->element = element; + ro->element = Py_NewRef(element); ro->cnt = cnt; return (PyObject *)ro; } @@ -4421,14 +4255,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; } @@ -4440,8 +4277,7 @@ repeat_next(repeatobject *ro) return NULL; if (ro->cnt > 0) ro->cnt--; - Py_INCREF(ro->element); - return ro->element; + return Py_NewRef(ro->element); } static PyObject * @@ -4471,6 +4307,7 @@ PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list( static PyObject * repeat_reduce(repeatobject *ro, PyObject *Py_UNUSED(ignored)) { + ITERTOOL_PICKLE_DEPRECATION; /* unpickle this so that a new repeat iterator is constructed with an * object, then call __setstate__ on it to set cnt */ @@ -4491,48 +4328,26 @@ 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 | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = repeat_slots, }; @@ -4547,8 +4362,6 @@ typedef struct { PyObject *fillvalue; } ziplongestobject; -static PyTypeObject ziplongest_type; - static PyObject * zip_longest_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { @@ -4613,24 +4426,26 @@ zip_longest_new(PyTypeObject *type, PyObject *args, PyObject *kwds) lz->tuplesize = tuplesize; lz->numactive = tuplesize; lz->result = result; - Py_INCREF(fillvalue); - lz->fillvalue = fillvalue; + lz->fillvalue = Py_NewRef(fillvalue); return (PyObject *)lz; } 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); - Py_TYPE(lz)->tp_free(lz); + tp->tp_free(lz); + Py_DECREF(tp); } static int zip_longest_traverse(ziplongestobject *lz, visitproc visit, void *arg) { + Py_VISIT(Py_TYPE(lz)); Py_VISIT(lz->ittuple); Py_VISIT(lz->result); Py_VISIT(lz->fillvalue); @@ -4656,8 +4471,7 @@ zip_longest_next(ziplongestobject *lz) for (i=0 ; i < tuplesize ; i++) { it = PyTuple_GET_ITEM(lz->ittuple, i); if (it == NULL) { - Py_INCREF(lz->fillvalue); - item = lz->fillvalue; + item = Py_NewRef(lz->fillvalue); } else { item = PyIter_Next(it); if (item == NULL) { @@ -4667,8 +4481,7 @@ zip_longest_next(ziplongestobject *lz) Py_DECREF(result); return NULL; } else { - Py_INCREF(lz->fillvalue); - item = lz->fillvalue; + item = Py_NewRef(lz->fillvalue); PyTuple_SET_ITEM(lz->ittuple, i, NULL); Py_DECREF(it); } @@ -4690,8 +4503,7 @@ zip_longest_next(ziplongestobject *lz) for (i=0 ; i < tuplesize ; i++) { it = PyTuple_GET_ITEM(lz->ittuple, i); if (it == NULL) { - Py_INCREF(lz->fillvalue); - item = lz->fillvalue; + item = Py_NewRef(lz->fillvalue); } else { item = PyIter_Next(it); if (item == NULL) { @@ -4701,8 +4513,7 @@ zip_longest_next(ziplongestobject *lz) Py_DECREF(result); return NULL; } else { - Py_INCREF(lz->fillvalue); - item = lz->fillvalue; + item = Py_NewRef(lz->fillvalue); PyTuple_SET_ITEM(lz->ittuple, i, NULL); Py_DECREF(it); } @@ -4717,7 +4528,7 @@ zip_longest_next(ziplongestobject *lz) static PyObject * zip_longest_reduce(ziplongestobject *lz, PyObject *Py_UNUSED(ignored)) { - + ITERTOOL_PICKLE_DEPRECATION; /* Create a new tuple with empty sequences where appropriate to pickle. * Then use setstate to set the fillvalue */ @@ -4744,6 +4555,7 @@ zip_longest_reduce(ziplongestobject *lz, PyObject *Py_UNUSED(ignored)) static PyObject * zip_longest_setstate(ziplongestobject *lz, PyObject *state) { + ITERTOOL_PICKLE_DEPRECATION; Py_INCREF(state); Py_XSETREF(lz->fillvalue, state); Py_RETURN_NONE; @@ -4768,48 +4580,25 @@ are exhausted, the fillvalue is substituted in their place. The fillvalue\n\ defaults to None or can be specified by a keyword argument.\n\ "); -static PyTypeObject ziplongest_type = { - PyVarObject_HEAD_INIT(NULL, 0) - "itertools.zip_longest", /* tp_name */ - sizeof(ziplongestobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)zip_longest_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 */ - zip_longest_doc, /* tp_doc */ - (traverseproc)zip_longest_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)zip_longest_next, /* tp_iternext */ - zip_longest_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 */ - zip_longest_new, /* tp_new */ - PyObject_GC_Del, /* tp_free */ +static PyType_Slot ziplongest_slots[] = { + {Py_tp_dealloc, zip_longest_dealloc}, + {Py_tp_getattro, PyObject_GenericGetAttr}, + {Py_tp_doc, (void *)zip_longest_doc}, + {Py_tp_traverse, zip_longest_traverse}, + {Py_tp_iter, PyObject_SelfIter}, + {Py_tp_iternext, zip_longest_next}, + {Py_tp_methods, zip_longest_methods}, + {Py_tp_new, zip_longest_new}, + {Py_tp_free, PyObject_GC_Del}, + {0, NULL}, +}; + +static PyType_Spec ziplongest_spec = { + .name = "itertools.zip_longest", + .basicsize = sizeof(ziplongestobject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = ziplongest_slots, }; @@ -4825,6 +4614,7 @@ repeat(elem [,n]) --> elem, elem, elem, ... endlessly or up to n times\n\ \n\ Iterators terminating on the shortest input sequence:\n\ accumulate(p[, func]) --> p0, p0+p1, p0+p1+p2\n\ +batched(p, n) --> [p0, p1, ..., p_n-1], [p_n, p_n+1, ..., p_2n-1], ...\n\ chain(p, q, ...) --> p0, p1, ... plast, q0, q1, ...\n\ chain.from_iterable([p, q, ...]) --> p0, p1, ... plast, q0, q1, ...\n\ compress(data, selectors) --> (d[0] if s[0]), (d[1] if s[1]), ...\n\ @@ -4847,45 +4637,114 @@ combinations_with_replacement(p, r)\n\ "); static int -itertoolsmodule_exec(PyObject *m) -{ - PyTypeObject *typelist[] = { - &accumulate_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, - &groupby_type, - &_grouper_type, - &tee_type, - &teedataobject_type - }; - - Py_SET_TYPE(&teedataobject_type, &PyType_Type); - - for (size_t i = 0; i < Py_ARRAY_LENGTH(typelist); i++) { - if (PyModule_AddType(m, typelist[i]) < 0) { - return -1; - } - } +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); + Py_VISIT(state->count_type); + Py_VISIT(state->cwr_type); + Py_VISIT(state->cycle_type); + Py_VISIT(state->dropwhile_type); + 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); + Py_VISIT(state->repeat_type); + 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; +} +static int +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); + Py_CLEAR(state->count_type); + Py_CLEAR(state->cwr_type); + Py_CLEAR(state->cycle_type); + Py_CLEAR(state->dropwhile_type); + 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); + Py_CLEAR(state->repeat_type); + 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; +} + +static void +itertoolsmodule_free(void *mod) +{ + (void)itertoolsmodule_clear((PyObject *)mod); +} + +#define ADD_TYPE(module, type, spec) \ +do { \ + type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec, NULL); \ + if (type == NULL) { \ + return -1; \ + } \ + if (PyModule_AddType(module, type) < 0) { \ + return -1; \ + } \ +} while (0) + +static int +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); + ADD_TYPE(mod, state->count_type, &count_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->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); + 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->teedataobject_type, &teedataobject_spec); + ADD_TYPE(mod, state->ziplongest_type, &ziplongest_spec); + + Py_SET_TYPE(state->teedataobject_type, &PyType_Type); return 0; } static struct PyModuleDef_Slot itertoolsmodule_slots[] = { {Py_mod_exec, itertoolsmodule_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, {0, NULL} }; @@ -4896,15 +4755,15 @@ static PyMethodDef module_methods[] = { static struct PyModuleDef itertoolsmodule = { - PyModuleDef_HEAD_INIT, - "itertools", - module_doc, - 0, - module_methods, - itertoolsmodule_slots, - NULL, - NULL, - NULL + .m_base = PyModuleDef_HEAD_INIT, + .m_name = "itertools", + .m_doc = module_doc, + .m_size = sizeof(itertools_state), + .m_methods = module_methods, + .m_slots = itertoolsmodule_slots, + .m_traverse = itertoolsmodule_traverse, + .m_clear = itertoolsmodule_clear, + .m_free = itertoolsmodule_free, }; PyMODINIT_FUNC |