Skip to content

Commit 50410bf

Browse files
pythongh-101277: Add groupby and _grouper types to module state
1 parent 99406f8 commit 50410bf

File tree

2 files changed

+123
-110
lines changed

2 files changed

+123
-110
lines changed

Modules/clinic/itertoolsmodule.c.h

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/itertoolsmodule.c

Lines changed: 118 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,33 @@
1010
by Raymond D. Hettinger <[email protected]>
1111
*/
1212

13+
typedef struct {
14+
PyTypeObject *groupby_type;
15+
PyTypeObject *_grouper_type;
16+
} itertools_state;
17+
18+
static inline itertools_state *
19+
get_module_state(PyObject *mod)
20+
{
21+
void *state = PyModule_GetState(mod);
22+
assert(state != NULL);
23+
return (itertools_state *)state;
24+
}
25+
26+
static struct PyModuleDef itertoolsmodule;
27+
static inline itertools_state *
28+
find_state_by_type(PyTypeObject *tp)
29+
{
30+
PyObject *mod = PyType_GetModuleByDef(tp, &itertoolsmodule);
31+
assert(mod != NULL);
32+
return get_module_state(mod);
33+
}
34+
#define clinic_state() (find_state_by_type(type))
35+
1336
/*[clinic input]
1437
module itertools
15-
class itertools.groupby "groupbyobject *" "&groupby_type"
16-
class itertools._grouper "_grouperobject *" "&_grouper_type"
38+
class itertools.groupby "groupbyobject *" "clinic_state()->groupby_type"
39+
class itertools._grouper "_grouperobject *" "clinic_state()->_grouper_type"
1740
class itertools.teedataobject "teedataobject *" "&teedataobject_type"
1841
class itertools._tee "teeobject *" "&tee_type"
1942
class itertools.batched "batchedobject *" "&batched_type"
@@ -31,10 +54,8 @@ class itertools.filterfalse "filterfalseobject *" "&filterfalse_type"
3154
class itertools.count "countobject *" "&count_type"
3255
class itertools.pairwise "pairwiseobject *" "&pairwise_type"
3356
[clinic start generated code]*/
34-
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=1168b274011ce21b]*/
57+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=424108522584b55b]*/
3558

36-
static PyTypeObject groupby_type;
37-
static PyTypeObject _grouper_type;
3859
static PyTypeObject teedataobject_type;
3960
static PyTypeObject tee_type;
4061
static PyTypeObject batched_type;
@@ -51,14 +72,8 @@ static PyTypeObject filterfalse_type;
5172
static PyTypeObject count_type;
5273
static PyTypeObject pairwise_type;
5374

54-
typedef struct {
55-
} itertools_state;
56-
57-
static itertools_state global_state;
58-
59-
#define GLOBAL_STATE (&global_state)
60-
6175
#include "clinic/itertoolsmodule.c.h"
76+
#undef clinic_state
6277

6378
/* batched object ************************************************************/
6479

@@ -421,18 +436,21 @@ itertools_groupby_impl(PyTypeObject *type, PyObject *it, PyObject *keyfunc)
421436
static void
422437
groupby_dealloc(groupbyobject *gbo)
423438
{
439+
PyTypeObject *tp = Py_TYPE(gbo);
424440
PyObject_GC_UnTrack(gbo);
425441
Py_XDECREF(gbo->it);
426442
Py_XDECREF(gbo->keyfunc);
427443
Py_XDECREF(gbo->tgtkey);
428444
Py_XDECREF(gbo->currkey);
429445
Py_XDECREF(gbo->currvalue);
430-
Py_TYPE(gbo)->tp_free(gbo);
446+
tp->tp_free(gbo);
447+
Py_DECREF(tp);
431448
}
432449

433450
static int
434451
groupby_traverse(groupbyobject *gbo, visitproc visit, void *arg)
435452
{
453+
Py_VISIT(Py_TYPE(gbo));
436454
Py_VISIT(gbo->it);
437455
Py_VISIT(gbo->keyfunc);
438456
Py_VISIT(gbo->tgtkey);
@@ -553,50 +571,26 @@ static PyMethodDef groupby_methods[] = {
553571
{NULL, NULL} /* sentinel */
554572
};
555573

556-
static PyTypeObject groupby_type = {
557-
PyVarObject_HEAD_INIT(NULL, 0)
558-
"itertools.groupby", /* tp_name */
559-
sizeof(groupbyobject), /* tp_basicsize */
560-
0, /* tp_itemsize */
561-
/* methods */
562-
(destructor)groupby_dealloc, /* tp_dealloc */
563-
0, /* tp_vectorcall_offset */
564-
0, /* tp_getattr */
565-
0, /* tp_setattr */
566-
0, /* tp_as_async */
567-
0, /* tp_repr */
568-
0, /* tp_as_number */
569-
0, /* tp_as_sequence */
570-
0, /* tp_as_mapping */
571-
0, /* tp_hash */
572-
0, /* tp_call */
573-
0, /* tp_str */
574-
PyObject_GenericGetAttr, /* tp_getattro */
575-
0, /* tp_setattro */
576-
0, /* tp_as_buffer */
577-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
578-
Py_TPFLAGS_BASETYPE, /* tp_flags */
579-
itertools_groupby__doc__, /* tp_doc */
580-
(traverseproc)groupby_traverse, /* tp_traverse */
581-
0, /* tp_clear */
582-
0, /* tp_richcompare */
583-
0, /* tp_weaklistoffset */
584-
PyObject_SelfIter, /* tp_iter */
585-
(iternextfunc)groupby_next, /* tp_iternext */
586-
groupby_methods, /* tp_methods */
587-
0, /* tp_members */
588-
0, /* tp_getset */
589-
0, /* tp_base */
590-
0, /* tp_dict */
591-
0, /* tp_descr_get */
592-
0, /* tp_descr_set */
593-
0, /* tp_dictoffset */
594-
0, /* tp_init */
595-
0, /* tp_alloc */
596-
itertools_groupby, /* tp_new */
597-
PyObject_GC_Del, /* tp_free */
574+
static PyType_Slot groupby_slots[] = {
575+
{Py_tp_dealloc, groupby_dealloc},
576+
{Py_tp_getattro, PyObject_GenericGetAttr},
577+
{Py_tp_doc, (void *)itertools_groupby__doc__},
578+
{Py_tp_traverse, groupby_traverse},
579+
{Py_tp_iter, PyObject_SelfIter},
580+
{Py_tp_iternext, groupby_next},
581+
{Py_tp_methods, groupby_methods},
582+
{Py_tp_new, itertools_groupby},
583+
{Py_tp_free, PyObject_GC_Del},
584+
{0, NULL},
598585
};
599586

587+
static PyType_Spec groupby_spec = {
588+
.name = "itertools.groupby",
589+
.basicsize= sizeof(groupbyobject),
590+
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE |
591+
Py_TPFLAGS_IMMUTABLETYPE),
592+
.slots = groupby_slots,
593+
};
600594

601595
/* _grouper object (internal) ************************************************/
602596

@@ -610,25 +604,25 @@ typedef struct {
610604
@classmethod
611605
itertools._grouper.__new__
612606
613-
parent: object(subclass_of='&groupby_type')
607+
parent: object(subclass_of='clinic_state()->groupby_type')
614608
tgtkey: object
615609
/
616610
[clinic start generated code]*/
617611

618612
static PyObject *
619613
itertools__grouper_impl(PyTypeObject *type, PyObject *parent,
620614
PyObject *tgtkey)
621-
/*[clinic end generated code: output=462efb1cdebb5914 input=dc180d7771fc8c59]*/
615+
/*[clinic end generated code: output=462efb1cdebb5914 input=626b30a78e38cf7d]*/
622616
{
623617
return _grouper_create((groupbyobject*) parent, tgtkey);
624618
}
625619

626620
static PyObject *
627621
_grouper_create(groupbyobject *parent, PyObject *tgtkey)
628622
{
629-
_grouperobject *igo;
630-
631-
igo = PyObject_GC_New(_grouperobject, &_grouper_type);
623+
PyTypeObject *tp = Py_TYPE(parent);
624+
itertools_state *state = find_state_by_type(tp);
625+
_grouperobject *igo = PyObject_GC_New(_grouperobject, state->_grouper_type);
632626
if (igo == NULL)
633627
return NULL;
634628
igo->parent = Py_NewRef(parent);
@@ -642,15 +636,18 @@ _grouper_create(groupbyobject *parent, PyObject *tgtkey)
642636
static void
643637
_grouper_dealloc(_grouperobject *igo)
644638
{
639+
PyTypeObject *tp = Py_TYPE(igo);
645640
PyObject_GC_UnTrack(igo);
646641
Py_DECREF(igo->parent);
647642
Py_DECREF(igo->tgtkey);
648643
PyObject_GC_Del(igo);
644+
Py_DECREF(tp);
649645
}
650646

651647
static int
652648
_grouper_traverse(_grouperobject *igo, visitproc visit, void *arg)
653649
{
650+
Py_VISIT(Py_TYPE(igo));
654651
Py_VISIT(igo->parent);
655652
Py_VISIT(igo->tgtkey);
656653
return 0;
@@ -698,48 +695,24 @@ static PyMethodDef _grouper_methods[] = {
698695
{NULL, NULL} /* sentinel */
699696
};
700697

698+
static PyType_Slot _grouper_slots[] = {
699+
{Py_tp_dealloc, _grouper_dealloc},
700+
{Py_tp_getattro, PyObject_GenericGetAttr},
701+
{Py_tp_traverse, _grouper_traverse},
702+
{Py_tp_iter, PyObject_SelfIter},
703+
{Py_tp_iternext, _grouper_next},
704+
{Py_tp_methods, _grouper_methods},
705+
{Py_tp_new, itertools__grouper},
706+
{Py_tp_free, PyObject_GC_Del},
707+
{0, NULL},
708+
};
701709

702-
static PyTypeObject _grouper_type = {
703-
PyVarObject_HEAD_INIT(NULL, 0)
704-
"itertools._grouper", /* tp_name */
705-
sizeof(_grouperobject), /* tp_basicsize */
706-
0, /* tp_itemsize */
707-
/* methods */
708-
(destructor)_grouper_dealloc, /* tp_dealloc */
709-
0, /* tp_vectorcall_offset */
710-
0, /* tp_getattr */
711-
0, /* tp_setattr */
712-
0, /* tp_as_async */
713-
0, /* tp_repr */
714-
0, /* tp_as_number */
715-
0, /* tp_as_sequence */
716-
0, /* tp_as_mapping */
717-
0, /* tp_hash */
718-
0, /* tp_call */
719-
0, /* tp_str */
720-
PyObject_GenericGetAttr, /* tp_getattro */
721-
0, /* tp_setattro */
722-
0, /* tp_as_buffer */
723-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
724-
0, /* tp_doc */
725-
(traverseproc)_grouper_traverse, /* tp_traverse */
726-
0, /* tp_clear */
727-
0, /* tp_richcompare */
728-
0, /* tp_weaklistoffset */
729-
PyObject_SelfIter, /* tp_iter */
730-
(iternextfunc)_grouper_next, /* tp_iternext */
731-
_grouper_methods, /* tp_methods */
732-
0, /* tp_members */
733-
0, /* tp_getset */
734-
0, /* tp_base */
735-
0, /* tp_dict */
736-
0, /* tp_descr_get */
737-
0, /* tp_descr_set */
738-
0, /* tp_dictoffset */
739-
0, /* tp_init */
740-
0, /* tp_alloc */
741-
itertools__grouper, /* tp_new */
742-
PyObject_GC_Del, /* tp_free */
710+
static PyType_Spec _grouper_spec = {
711+
.name = "itertools._grouper",
712+
.basicsize = sizeof(_grouperobject),
713+
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
714+
Py_TPFLAGS_IMMUTABLETYPE),
715+
.slots = _grouper_slots,
743716
};
744717

745718

@@ -4986,8 +4959,47 @@ combinations_with_replacement(p, r)\n\
49864959
");
49874960

49884961
static int
4989-
itertoolsmodule_exec(PyObject *m)
4962+
itertoolsmodule_traverse(PyObject *mod, visitproc visit, void *arg)
4963+
{
4964+
itertools_state *state = get_module_state(mod);
4965+
Py_VISIT(state->groupby_type);
4966+
Py_VISIT(state->_grouper_type);
4967+
return 0;
4968+
}
4969+
4970+
static int
4971+
itertoolsmodule_clear(PyObject *mod)
4972+
{
4973+
itertools_state *state = get_module_state(mod);
4974+
Py_CLEAR(state->groupby_type);
4975+
Py_CLEAR(state->_grouper_type);
4976+
return 0;
4977+
}
4978+
4979+
static void
4980+
itertoolsmodule_free(void *mod)
4981+
{
4982+
(void)itertoolsmodule_clear((PyObject *)mod);
4983+
}
4984+
4985+
#define ADD_TYPE(module, type, spec) \
4986+
do { \
4987+
type = (PyTypeObject *)PyType_FromModuleAndSpec(module, spec, NULL); \
4988+
if (type == NULL) { \
4989+
return -1; \
4990+
} \
4991+
if (PyModule_AddType(module, type) < 0) { \
4992+
return -1; \
4993+
} \
4994+
} while (0)
4995+
4996+
static int
4997+
itertoolsmodule_exec(PyObject *mod)
49904998
{
4999+
itertools_state *state = get_module_state(mod);
5000+
ADD_TYPE(mod, state->groupby_type, &groupby_spec);
5001+
ADD_TYPE(mod, state->_grouper_type, &_grouper_spec);
5002+
49915003
PyTypeObject *typelist[] = {
49925004
&accumulate_type,
49935005
&batched_type,
@@ -5007,16 +5019,14 @@ itertoolsmodule_exec(PyObject *m)
50075019
&permutations_type,
50085020
&product_type,
50095021
&repeat_type,
5010-
&groupby_type,
5011-
&_grouper_type,
50125022
&tee_type,
50135023
&teedataobject_type
50145024
};
50155025

50165026
Py_SET_TYPE(&teedataobject_type, &PyType_Type);
50175027

50185028
for (size_t i = 0; i < Py_ARRAY_LENGTH(typelist); i++) {
5019-
if (PyModule_AddType(m, typelist[i]) < 0) {
5029+
if (PyModule_AddType(mod, typelist[i]) < 0) {
50205030
return -1;
50215031
}
50225032
}
@@ -5042,6 +5052,9 @@ static struct PyModuleDef itertoolsmodule = {
50425052
.m_size = sizeof(itertools_state),
50435053
.m_methods = module_methods,
50445054
.m_slots = itertoolsmodule_slots,
5055+
.m_traverse = itertoolsmodule_traverse,
5056+
.m_clear = itertoolsmodule_clear,
5057+
.m_free = itertoolsmodule_free,
50455058
};
50465059

50475060
PyMODINIT_FUNC

0 commit comments

Comments
 (0)