summaryrefslogtreecommitdiffstats
path: root/Modules/_collectionsmodule.c
diff options
context:
space:
mode:
authorErlend E. Aasland <erlend.aasland@protonmail.com>2023-04-12 12:51:28 (GMT)
committerGitHub <noreply@github.com>2023-04-12 12:51:28 (GMT)
commit52f96d3ea39fea4c16e26b7b10bd2db09726bd7c (patch)
treedc5724301af87f55745c36adf8ae2d2c034987e2 /Modules/_collectionsmodule.c
parent411b1692811b2ecac59cb0df0f920861c7cf179a (diff)
downloadcpython-52f96d3ea39fea4c16e26b7b10bd2db09726bd7c.zip
cpython-52f96d3ea39fea4c16e26b7b10bd2db09726bd7c.tar.gz
cpython-52f96d3ea39fea4c16e26b7b10bd2db09726bd7c.tar.bz2
gh-103092: Isolate `_collections` (#103093)
Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
Diffstat (limited to 'Modules/_collectionsmodule.c')
-rw-r--r--Modules/_collectionsmodule.c555
1 files changed, 279 insertions, 276 deletions
diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c
index 9d8aef1..a9b1425 100644
--- a/Modules/_collectionsmodule.c
+++ b/Modules/_collectionsmodule.c
@@ -1,17 +1,56 @@
#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 "structmember.h" // PyMemberDef
#include <stddef.h>
+typedef struct {
+ PyTypeObject *deque_type;
+ PyTypeObject *defdict_type;
+ PyTypeObject *dequeiter_type;
+ PyTypeObject *dequereviter_type;
+ PyTypeObject *tuplegetter_type;
+} collections_state;
+
+static inline collections_state *
+get_module_state(PyObject *mod)
+{
+ void *state = _PyModule_GetState(mod);
+ assert(state != NULL);
+ return (collections_state *)state;
+}
+
+static inline collections_state *
+get_module_state_by_cls(PyTypeObject *cls)
+{
+ void *state = _PyType_GetModuleState(cls);
+ assert(state != NULL);
+ return (collections_state *)state;
+}
+
+static struct PyModuleDef _collectionsmodule;
+
+static inline collections_state *
+find_module_state_by_def(PyTypeObject *type)
+{
+ PyObject *mod = PyType_GetModuleByDef(type, &_collectionsmodule);
+ assert(mod != NULL);
+ return get_module_state(mod);
+}
+
/*[clinic input]
module _collections
-class _tuplegetter "_tuplegetterobject *" "&tuplegetter_type"
+class _tuplegetter "_tuplegetterobject *" "clinic_state()->tuplegetter_type"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a8ece4ccad7e30ac]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7356042a89862e0e]*/
-static PyTypeObject tuplegetter_type;
+/* We can safely assume type to be the defining class,
+ * since tuplegetter is not a base type */
+#define clinic_state() (get_module_state_by_cls(type))
#include "clinic/_collectionsmodule.c.h"
+#undef clinic_state
/* collections module implementation of a deque() datatype
Written and maintained by Raymond D. Hettinger <python@rcn.com>
@@ -94,8 +133,6 @@ typedef struct {
PyObject *weakreflist;
} dequeobject;
-static PyTypeObject deque_type;
-
/* For debug builds, add error checking to track the endpoints
* in the chain of links. The goal is to make sure that link
* assignments only take place at endpoints so that links already
@@ -484,11 +521,13 @@ deque_copy(PyObject *deque, PyObject *Py_UNUSED(ignored))
{
PyObject *result;
dequeobject *old_deque = (dequeobject *)deque;
- if (Py_IS_TYPE(deque, &deque_type)) {
+ collections_state *state = find_module_state_by_def(Py_TYPE(deque));
+ if (Py_IS_TYPE(deque, state->deque_type)) {
dequeobject *new_deque;
PyObject *rv;
- new_deque = (dequeobject *)deque_new(&deque_type, (PyObject *)NULL, (PyObject *)NULL);
+ new_deque = (dequeobject *)deque_new(state->deque_type,
+ (PyObject *)NULL, (PyObject *)NULL);
if (new_deque == NULL)
return NULL;
new_deque->maxlen = old_deque->maxlen;
@@ -511,7 +550,7 @@ deque_copy(PyObject *deque, PyObject *Py_UNUSED(ignored))
else
result = PyObject_CallFunction((PyObject *)(Py_TYPE(deque)), "Oi",
deque, old_deque->maxlen, NULL);
- if (result != NULL && !PyObject_TypeCheck(result, &deque_type)) {
+ if (result != NULL && !PyObject_TypeCheck(result, state->deque_type)) {
PyErr_Format(PyExc_TypeError,
"%.200s() must return a deque, not %.200s",
Py_TYPE(deque)->tp_name, Py_TYPE(result)->tp_name);
@@ -529,7 +568,8 @@ deque_concat(dequeobject *deque, PyObject *other)
PyObject *new_deque, *result;
int rv;
- rv = PyObject_IsInstance(other, (PyObject *)&deque_type);
+ collections_state *state = find_module_state_by_def(Py_TYPE(deque));
+ rv = PyObject_IsInstance(other, (PyObject *)state->deque_type);
if (rv <= 0) {
if (rv == 0) {
PyErr_Format(PyExc_TypeError,
@@ -1288,6 +1328,7 @@ deque_ass_item(dequeobject *deque, Py_ssize_t i, PyObject *v)
static void
deque_dealloc(dequeobject *deque)
{
+ PyTypeObject *tp = Py_TYPE(deque);
Py_ssize_t i;
PyObject_GC_UnTrack(deque);
@@ -1303,12 +1344,15 @@ deque_dealloc(dequeobject *deque)
for (i=0 ; i < deque->numfreeblocks ; i++) {
PyMem_Free(deque->freeblocks[i]);
}
- Py_TYPE(deque)->tp_free(deque);
+ tp->tp_free(deque);
+ Py_DECREF(tp);
}
static int
deque_traverse(dequeobject *deque, visitproc visit, void *arg)
{
+ Py_VISIT(Py_TYPE(deque));
+
block *b;
PyObject *item;
Py_ssize_t index;
@@ -1393,8 +1437,9 @@ deque_richcompare(PyObject *v, PyObject *w, int op)
Py_ssize_t vs, ws;
int b, cmp=-1;
- if (!PyObject_TypeCheck(v, &deque_type) ||
- !PyObject_TypeCheck(w, &deque_type)) {
+ collections_state *state = find_module_state_by_def(Py_TYPE(v));
+ if (!PyObject_TypeCheck(v, state->deque_type) ||
+ !PyObject_TypeCheck(w, state->deque_type)) {
Py_RETURN_NOTIMPLEMENTED;
}
@@ -1537,19 +1582,6 @@ static PyGetSetDef deque_getset[] = {
{0}
};
-static PySequenceMethods deque_as_sequence = {
- (lenfunc)deque_len, /* sq_length */
- (binaryfunc)deque_concat, /* sq_concat */
- (ssizeargfunc)deque_repeat, /* sq_repeat */
- (ssizeargfunc)deque_item, /* sq_item */
- 0, /* sq_slice */
- (ssizeobjargproc)deque_ass_item, /* sq_ass_item */
- 0, /* sq_ass_slice */
- (objobjproc)deque_contains, /* sq_contains */
- (binaryfunc)deque_inplace_concat, /* sq_inplace_concat */
- (ssizeargfunc)deque_inplace_repeat, /* sq_inplace_repeat */
-};
-
static PyObject *deque_iter(dequeobject *deque);
static PyObject *deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored));
PyDoc_STRVAR(reversed_doc,
@@ -1597,54 +1629,53 @@ static PyMethodDef deque_methods[] = {
{NULL, NULL} /* sentinel */
};
+static PyMemberDef deque_members[] = {
+ {"__weaklistoffset__", T_PYSSIZET, offsetof(dequeobject, weakreflist), READONLY},
+ {NULL},
+};
+
PyDoc_STRVAR(deque_doc,
"deque([iterable[, maxlen]]) --> deque object\n\
\n\
A list-like sequence optimized for data accesses near its endpoints.");
-static PyTypeObject deque_type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "collections.deque", /* tp_name */
- sizeof(dequeobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)deque_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- deque_repr, /* tp_repr */
- 0, /* tp_as_number */
- &deque_as_sequence, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- PyObject_HashNotImplemented, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
- Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_SEQUENCE,
- /* tp_flags */
- deque_doc, /* tp_doc */
- (traverseproc)deque_traverse, /* tp_traverse */
- (inquiry)deque_clear, /* tp_clear */
- (richcmpfunc)deque_richcompare, /* tp_richcompare */
- offsetof(dequeobject, weakreflist), /* tp_weaklistoffset*/
- (getiterfunc)deque_iter, /* tp_iter */
- 0, /* tp_iternext */
- deque_methods, /* tp_methods */
- 0, /* tp_members */
- deque_getset, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)deque_init, /* tp_init */
- PyType_GenericAlloc, /* tp_alloc */
- deque_new, /* tp_new */
- PyObject_GC_Del, /* tp_free */
+static PyType_Slot deque_slots[] = {
+ {Py_tp_dealloc, deque_dealloc},
+ {Py_tp_repr, deque_repr},
+ {Py_tp_hash, PyObject_HashNotImplemented},
+ {Py_tp_getattro, PyObject_GenericGetAttr},
+ {Py_tp_doc, (void *)deque_doc},
+ {Py_tp_traverse, deque_traverse},
+ {Py_tp_clear, deque_clear},
+ {Py_tp_richcompare, deque_richcompare},
+ {Py_tp_iter, deque_iter},
+ {Py_tp_getset, deque_getset},
+ {Py_tp_init, deque_init},
+ {Py_tp_alloc, PyType_GenericAlloc},
+ {Py_tp_new, deque_new},
+ {Py_tp_free, PyObject_GC_Del},
+ {Py_tp_methods, deque_methods},
+ {Py_tp_members, deque_members},
+
+ // Sequence protocol
+ {Py_sq_length, deque_len},
+ {Py_sq_concat, deque_concat},
+ {Py_sq_repeat, deque_repeat},
+ {Py_sq_item, deque_item},
+ {Py_sq_ass_item, deque_ass_item},
+ {Py_sq_contains, deque_contains},
+ {Py_sq_inplace_concat, deque_inplace_concat},
+ {Py_sq_inplace_repeat, deque_inplace_repeat},
+ {0, NULL},
+};
+
+static PyType_Spec deque_spec = {
+ .name = "collections.deque",
+ .basicsize = sizeof(dequeobject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_SEQUENCE |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = deque_slots,
};
/*********************** Deque Iterator **************************/
@@ -1658,14 +1689,13 @@ typedef struct {
Py_ssize_t counter; /* number of items remaining for iteration */
} dequeiterobject;
-static PyTypeObject dequeiter_type;
-
static PyObject *
deque_iter(dequeobject *deque)
{
dequeiterobject *it;
- it = PyObject_GC_New(dequeiterobject, &dequeiter_type);
+ collections_state *state = find_module_state_by_def(Py_TYPE(deque));
+ it = PyObject_GC_New(dequeiterobject, state->dequeiter_type);
if (it == NULL)
return NULL;
it->b = deque->leftblock;
@@ -1680,17 +1710,27 @@ deque_iter(dequeobject *deque)
static int
dequeiter_traverse(dequeiterobject *dio, visitproc visit, void *arg)
{
+ Py_VISIT(Py_TYPE(dio));
Py_VISIT(dio->deque);
return 0;
}
+static int
+dequeiter_clear(dequeiterobject *dio)
+{
+ Py_CLEAR(dio->deque);
+ return 0;
+}
+
static void
dequeiter_dealloc(dequeiterobject *dio)
{
/* bpo-31095: UnTrack is needed before calling any callbacks */
+ PyTypeObject *tp = Py_TYPE(dio);
PyObject_GC_UnTrack(dio);
- Py_XDECREF(dio->deque);
+ (void)dequeiter_clear(dio);
PyObject_GC_Del(dio);
+ Py_DECREF(tp);
}
static PyObject *
@@ -1726,9 +1766,10 @@ dequeiter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_ssize_t i, index=0;
PyObject *deque;
dequeiterobject *it;
- if (!PyArg_ParseTuple(args, "O!|n", &deque_type, &deque, &index))
+ collections_state *state = get_module_state_by_cls(type);
+ if (!PyArg_ParseTuple(args, "O!|n", state->deque_type, &deque, &index))
return NULL;
- assert(type == &dequeiter_type);
+ assert(type == state->dequeiter_type);
it = (dequeiterobject*)deque_iter((dequeobject *)deque);
if (!it)
@@ -1769,59 +1810,35 @@ static PyMethodDef dequeiter_methods[] = {
{NULL, NULL} /* sentinel */
};
-static PyTypeObject dequeiter_type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_collections._deque_iterator", /* tp_name */
- sizeof(dequeiterobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)dequeiter_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)dequeiter_traverse, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- PyObject_SelfIter, /* tp_iter */
- (iternextfunc)dequeiter_next, /* tp_iternext */
- dequeiter_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 */
- dequeiter_new, /* tp_new */
- 0,
+static PyType_Slot dequeiter_slots[] = {
+ {Py_tp_dealloc, dequeiter_dealloc},
+ {Py_tp_getattro, PyObject_GenericGetAttr},
+ {Py_tp_traverse, dequeiter_traverse},
+ {Py_tp_clear, dequeiter_clear},
+ {Py_tp_iter, PyObject_SelfIter},
+ {Py_tp_iternext, dequeiter_next},
+ {Py_tp_methods, dequeiter_methods},
+ {Py_tp_new, dequeiter_new},
+ {0, NULL},
};
-/*********************** Deque Reverse Iterator **************************/
+static PyType_Spec dequeiter_spec = {
+ .name = "collections._deque_iterator",
+ .basicsize = sizeof(dequeiterobject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = dequeiter_slots,
+};
-static PyTypeObject dequereviter_type;
+/*********************** Deque Reverse Iterator **************************/
static PyObject *
deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored))
{
dequeiterobject *it;
+ collections_state *state = find_module_state_by_def(Py_TYPE(deque));
- it = PyObject_GC_New(dequeiterobject, &dequereviter_type);
+ it = PyObject_GC_New(dequeiterobject, state->dequereviter_type);
if (it == NULL)
return NULL;
it->b = deque->rightblock;
@@ -1866,9 +1883,10 @@ dequereviter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_ssize_t i, index=0;
PyObject *deque;
dequeiterobject *it;
- if (!PyArg_ParseTuple(args, "O!|n", &deque_type, &deque, &index))
+ collections_state *state = get_module_state_by_cls(type);
+ if (!PyArg_ParseTuple(args, "O!|n", state->deque_type, &deque, &index))
return NULL;
- assert(type == &dequereviter_type);
+ assert(type == state->dequereviter_type);
it = (dequeiterobject*)deque_reviter((dequeobject *)deque, NULL);
if (!it)
@@ -1889,47 +1907,24 @@ dequereviter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return (PyObject*)it;
}
-static PyTypeObject dequereviter_type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_collections._deque_reverse_iterator", /* tp_name */
- sizeof(dequeiterobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)dequeiter_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)dequeiter_traverse, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- PyObject_SelfIter, /* tp_iter */
- (iternextfunc)dequereviter_next, /* tp_iternext */
- dequeiter_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 */
- dequereviter_new, /* tp_new */
- 0,
+static PyType_Slot dequereviter_slots[] = {
+ {Py_tp_dealloc, dequeiter_dealloc},
+ {Py_tp_getattro, PyObject_GenericGetAttr},
+ {Py_tp_traverse, dequeiter_traverse},
+ {Py_tp_clear, dequeiter_clear},
+ {Py_tp_iter, PyObject_SelfIter},
+ {Py_tp_iternext, dequereviter_next},
+ {Py_tp_methods, dequeiter_methods},
+ {Py_tp_new, dequereviter_new},
+ {0, NULL},
+};
+
+static PyType_Spec dequereviter_spec = {
+ .name = "collections._deque_reverse_iterator",
+ .basicsize = sizeof(dequeiterobject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = dequereviter_slots,
};
/* defaultdict type *********************************************************/
@@ -1939,8 +1934,6 @@ typedef struct {
PyObject *default_factory;
} defdictobject;
-static PyTypeObject defdict_type; /* Forward */
-
PyDoc_STRVAR(defdict_missing_doc,
"__missing__(key) # Called by __getitem__ for missing key; pseudo-code:\n\
if self.default_factory is None: raise KeyError((key,))\n\
@@ -2071,9 +2064,11 @@ static void
defdict_dealloc(defdictobject *dd)
{
/* bpo-31095: UnTrack is needed before calling any callbacks */
+ PyTypeObject *tp = Py_TYPE(dd);
PyObject_GC_UnTrack(dd);
Py_CLEAR(dd->default_factory);
PyDict_Type.tp_dealloc((PyObject *)dd);
+ Py_DECREF(tp);
}
static PyObject *
@@ -2117,11 +2112,24 @@ static PyObject*
defdict_or(PyObject* left, PyObject* right)
{
PyObject *self, *other;
- if (PyObject_TypeCheck(left, &defdict_type)) {
+
+ // Find module state
+ PyTypeObject *tp = Py_TYPE(left);
+ PyObject *mod = PyType_GetModuleByDef(tp, &_collectionsmodule);
+ if (mod == NULL) {
+ PyErr_Clear();
+ tp = Py_TYPE(right);
+ mod = PyType_GetModuleByDef(tp, &_collectionsmodule);
+ }
+ assert(mod != NULL);
+ collections_state *state = get_module_state(mod);
+
+ if (PyObject_TypeCheck(left, state->defdict_type)) {
self = left;
other = right;
}
else {
+ assert(PyObject_TypeCheck(right, state->defdict_type));
self = right;
other = left;
}
@@ -2141,13 +2149,10 @@ defdict_or(PyObject* left, PyObject* right)
return new;
}
-static PyNumberMethods defdict_as_number = {
- .nb_or = defdict_or,
-};
-
static int
defdict_traverse(PyObject *self, visitproc visit, void *arg)
{
+ Py_VISIT(Py_TYPE(self));
Py_VISIT(((defdictobject *)self)->default_factory);
return PyDict_Type.tp_traverse(self, visit, arg);
}
@@ -2203,48 +2208,28 @@ passed to the dict constructor, including keyword arguments.\n\
/* See comment in xxsubtype.c */
#define DEFERRED_ADDRESS(ADDR) 0
-static PyTypeObject defdict_type = {
- PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
- "collections.defaultdict", /* tp_name */
- sizeof(defdictobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)defdict_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- (reprfunc)defdict_repr, /* tp_repr */
- &defdict_as_number, /* 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_BASETYPE | Py_TPFLAGS_HAVE_GC,
- /* tp_flags */
- defdict_doc, /* tp_doc */
- defdict_traverse, /* tp_traverse */
- (inquiry)defdict_tp_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset*/
- 0, /* tp_iter */
- 0, /* tp_iternext */
- defdict_methods, /* tp_methods */
- defdict_members, /* tp_members */
- 0, /* tp_getset */
- DEFERRED_ADDRESS(&PyDict_Type), /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- defdict_init, /* tp_init */
- PyType_GenericAlloc, /* tp_alloc */
- 0, /* tp_new */
- PyObject_GC_Del, /* tp_free */
+static PyType_Slot defdict_slots[] = {
+ {Py_tp_dealloc, defdict_dealloc},
+ {Py_tp_repr, defdict_repr},
+ {Py_nb_or, defdict_or},
+ {Py_tp_getattro, PyObject_GenericGetAttr},
+ {Py_tp_doc, (void *)defdict_doc},
+ {Py_tp_traverse, defdict_traverse},
+ {Py_tp_clear, defdict_tp_clear},
+ {Py_tp_methods, defdict_methods},
+ {Py_tp_members, defdict_members},
+ {Py_tp_init, defdict_init},
+ {Py_tp_alloc, PyType_GenericAlloc},
+ {Py_tp_free, PyObject_GC_Del},
+ {0, NULL},
+};
+
+static PyType_Spec defdict_spec = {
+ .name = "collections.defaultdict",
+ .basicsize = sizeof(defdictobject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = defdict_slots,
};
/* helper function for Counter *********************************************/
@@ -2442,6 +2427,7 @@ static int
tuplegetter_traverse(PyObject *self, visitproc visit, void *arg)
{
_tuplegetterobject *tuplegetter = (_tuplegetterobject *)self;
+ Py_VISIT(Py_TYPE(tuplegetter));
Py_VISIT(tuplegetter->doc);
return 0;
}
@@ -2457,9 +2443,11 @@ tuplegetter_clear(PyObject *self)
static void
tuplegetter_dealloc(_tuplegetterobject *self)
{
+ PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
tuplegetter_clear((PyObject*)self);
- Py_TYPE(self)->tp_free((PyObject*)self);
+ tp->tp_free((PyObject*)self);
+ Py_DECREF(tp);
}
static PyObject*
@@ -2487,52 +2475,60 @@ static PyMethodDef tuplegetter_methods[] = {
{NULL},
};
-static PyTypeObject tuplegetter_type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_collections._tuplegetter", /* tp_name */
- sizeof(_tuplegetterobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)tuplegetter_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- (reprfunc)tuplegetter_repr, /* 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 */
- 0, /* tp_doc */
- (traverseproc)tuplegetter_traverse, /* tp_traverse */
- (inquiry)tuplegetter_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- tuplegetter_methods, /* tp_methods */
- tuplegetter_members, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- tuplegetter_descr_get, /* tp_descr_get */
- tuplegetter_descr_set, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- tuplegetter_new, /* tp_new */
- 0,
+static PyType_Slot tuplegetter_slots[] = {
+ {Py_tp_dealloc, tuplegetter_dealloc},
+ {Py_tp_repr, tuplegetter_repr},
+ {Py_tp_traverse, tuplegetter_traverse},
+ {Py_tp_clear, tuplegetter_clear},
+ {Py_tp_methods, tuplegetter_methods},
+ {Py_tp_members, tuplegetter_members},
+ {Py_tp_descr_get, tuplegetter_descr_get},
+ {Py_tp_descr_set, tuplegetter_descr_set},
+ {Py_tp_new, tuplegetter_new},
+ {0, NULL},
+};
+
+static PyType_Spec tuplegetter_spec = {
+ .name = "collections._tuplegetter",
+ .basicsize = sizeof(_tuplegetterobject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = tuplegetter_slots,
};
/* module level code ********************************************************/
+static int
+collections_traverse(PyObject *mod, visitproc visit, void *arg)
+{
+ collections_state *state = get_module_state(mod);
+ Py_VISIT(state->deque_type);
+ Py_VISIT(state->defdict_type);
+ Py_VISIT(state->dequeiter_type);
+ Py_VISIT(state->dequereviter_type);
+ Py_VISIT(state->tuplegetter_type);
+ return 0;
+}
+
+static int
+collections_clear(PyObject *mod)
+{
+ collections_state *state = get_module_state(mod);
+ Py_CLEAR(state->deque_type);
+ Py_CLEAR(state->defdict_type);
+ Py_CLEAR(state->dequeiter_type);
+ Py_CLEAR(state->dequereviter_type);
+ Py_CLEAR(state->tuplegetter_type);
+ return 0;
+}
+
+static void
+collections_free(void *module)
+{
+ collections_clear((PyObject *)module);
+}
+
PyDoc_STRVAR(collections_doc,
"High performance data structures.\n\
- deque: ordered collection accessible from endpoints only\n\
@@ -2544,43 +2540,50 @@ static struct PyMethodDef collections_methods[] = {
{NULL, NULL} /* sentinel */
};
+#define ADD_TYPE(MOD, SPEC, TYPE, BASE) do { \
+ TYPE = (PyTypeObject *)PyType_FromMetaclass(NULL, MOD, SPEC, \
+ (PyObject *)BASE); \
+ if (TYPE == NULL) { \
+ return -1; \
+ } \
+ if (PyModule_AddType(MOD, TYPE) < 0) { \
+ return -1; \
+ } \
+} while (0)
+
static int
collections_exec(PyObject *module) {
- PyTypeObject *typelist[] = {
- &deque_type,
- &defdict_type,
- &PyODict_Type,
- &dequeiter_type,
- &dequereviter_type,
- &tuplegetter_type
- };
-
- defdict_type.tp_base = &PyDict_Type;
-
- for (size_t i = 0; i < Py_ARRAY_LENGTH(typelist); i++) {
- if (PyModule_AddType(module, typelist[i]) < 0) {
- return -1;
- }
+ collections_state *state = get_module_state(module);
+ ADD_TYPE(module, &deque_spec, state->deque_type, NULL);
+ ADD_TYPE(module, &defdict_spec, state->defdict_type, &PyDict_Type);
+ ADD_TYPE(module, &dequeiter_spec, state->dequeiter_type, NULL);
+ ADD_TYPE(module, &dequereviter_spec, state->dequereviter_type, NULL);
+ ADD_TYPE(module, &tuplegetter_spec, state->tuplegetter_type, NULL);
+
+ if (PyModule_AddType(module, &PyODict_Type) < 0) {
+ return -1;
}
return 0;
}
+#undef ADD_TYPE
+
static struct PyModuleDef_Slot collections_slots[] = {
{Py_mod_exec, collections_exec},
{0, NULL}
};
static struct PyModuleDef _collectionsmodule = {
- PyModuleDef_HEAD_INIT,
- "_collections",
- collections_doc,
- 0,
- collections_methods,
- collections_slots,
- NULL,
- NULL,
- NULL
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "_collections",
+ .m_doc = collections_doc,
+ .m_size = sizeof(collections_state),
+ .m_methods = collections_methods,
+ .m_slots = collections_slots,
+ .m_traverse = collections_traverse,
+ .m_clear = collections_clear,
+ .m_free = collections_free,
};
PyMODINIT_FUNC