gh-134160: Add more comments for the xxlimited module (GH-140214)
This commit is contained in:
@@ -14,7 +14,9 @@
|
|||||||
This module roughly corresponds to::
|
This module roughly corresponds to::
|
||||||
|
|
||||||
class Xxo:
|
class Xxo:
|
||||||
"""A class that explicitly stores attributes in an internal dict"""
|
"""A class that explicitly stores attributes in an internal dict
|
||||||
|
(to simulate custom attribute handling).
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# In the C class, "_x_attr" is not accessible from Python code
|
# In the C class, "_x_attr" is not accessible from Python code
|
||||||
@@ -85,13 +87,16 @@ typedef struct {
|
|||||||
// Instance state
|
// Instance state
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
PyObject *x_attr; /* Attributes dictionary */
|
PyObject *x_attr; /* Attributes dictionary.
|
||||||
|
* May be NULL, which acts as an
|
||||||
|
* empty dict.
|
||||||
|
*/
|
||||||
char x_buffer[BUFSIZE]; /* buffer for Py_buffer */
|
char x_buffer[BUFSIZE]; /* buffer for Py_buffer */
|
||||||
Py_ssize_t x_exports; /* how many buffer are exported */
|
Py_ssize_t x_exports; /* how many buffer are exported */
|
||||||
} XxoObject;
|
} XxoObject;
|
||||||
|
|
||||||
#define XxoObject_CAST(op) ((XxoObject *)(op))
|
#define XxoObject_CAST(op) ((XxoObject *)(op))
|
||||||
// XXX: no good way to do this yet
|
// TODO: full support for type-checking was added in 3.14 (Py_tp_token)
|
||||||
// #define XxoObject_Check(v) Py_IS_TYPE(v, Xxo_Type)
|
// #define XxoObject_Check(v) Py_IS_TYPE(v, Xxo_Type)
|
||||||
|
|
||||||
static XxoObject *
|
static XxoObject *
|
||||||
@@ -112,8 +117,13 @@ newXxoObject(PyObject *module)
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Xxo finalization */
|
/* Xxo finalization.
|
||||||
|
*
|
||||||
|
* Types that store references to other PyObjects generally need to implement
|
||||||
|
* the GC slots: traverse, clear, dealloc, and (optionally) finalize.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// traverse: Visit all references from an object, including its type
|
||||||
static int
|
static int
|
||||||
Xxo_traverse(PyObject *op, visitproc visit, void *arg)
|
Xxo_traverse(PyObject *op, visitproc visit, void *arg)
|
||||||
{
|
{
|
||||||
@@ -126,6 +136,7 @@ Xxo_traverse(PyObject *op, visitproc visit, void *arg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clear: drop references in order to break all reference cycles
|
||||||
static int
|
static int
|
||||||
Xxo_clear(PyObject *op)
|
Xxo_clear(PyObject *op)
|
||||||
{
|
{
|
||||||
@@ -134,6 +145,8 @@ Xxo_clear(PyObject *op)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// finalize: like clear, but should leave the object in a consistent state.
|
||||||
|
// Equivalent to `__del__` in Python.
|
||||||
static void
|
static void
|
||||||
Xxo_finalize(PyObject *op)
|
Xxo_finalize(PyObject *op)
|
||||||
{
|
{
|
||||||
@@ -141,6 +154,7 @@ Xxo_finalize(PyObject *op)
|
|||||||
Py_CLEAR(self->x_attr);
|
Py_CLEAR(self->x_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dealloc: drop all remaining references and free memory
|
||||||
static void
|
static void
|
||||||
Xxo_dealloc(PyObject *self)
|
Xxo_dealloc(PyObject *self)
|
||||||
{
|
{
|
||||||
@@ -155,6 +169,7 @@ Xxo_dealloc(PyObject *self)
|
|||||||
|
|
||||||
/* Xxo attribute handling */
|
/* Xxo attribute handling */
|
||||||
|
|
||||||
|
// Get an attribute.
|
||||||
static PyObject *
|
static PyObject *
|
||||||
Xxo_getattro(PyObject *op, PyObject *name)
|
Xxo_getattro(PyObject *op, PyObject *name)
|
||||||
{
|
{
|
||||||
@@ -168,9 +183,12 @@ Xxo_getattro(PyObject *op, PyObject *name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Fall back to generic implementation (this handles special attributes,
|
||||||
|
// raising AttributeError, etc.)
|
||||||
return PyObject_GenericGetAttr(op, name);
|
return PyObject_GenericGetAttr(op, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set or delete an attribute.
|
||||||
static int
|
static int
|
||||||
Xxo_setattro(PyObject *op, PyObject *name, PyObject *v)
|
Xxo_setattro(PyObject *op, PyObject *name, PyObject *v)
|
||||||
{
|
{
|
||||||
@@ -198,7 +216,9 @@ Xxo_setattro(PyObject *op, PyObject *name, PyObject *v)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Xxo methods */
|
/* Xxo methods: C functions plus a PyMethodDef array that lists them and
|
||||||
|
* specifies metadata.
|
||||||
|
*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
Xxo_demo(PyObject *op, PyTypeObject *defining_class,
|
Xxo_demo(PyObject *op, PyTypeObject *defining_class,
|
||||||
@@ -234,7 +254,10 @@ static PyMethodDef Xxo_methods[] = {
|
|||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Xxo buffer interface */
|
/* Xxo buffer interface: C functions later referenced from PyType_Slot array.
|
||||||
|
* Other interfaces (e.g. for sequence-like or number-like types) are defined
|
||||||
|
* similarly.
|
||||||
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
Xxo_getbuffer(PyObject *op, Py_buffer *view, int flags)
|
Xxo_getbuffer(PyObject *op, Py_buffer *view, int flags)
|
||||||
@@ -300,6 +323,7 @@ static PyType_Spec Xxo_Type_spec = {
|
|||||||
/* Str type definition*/
|
/* Str type definition*/
|
||||||
|
|
||||||
static PyType_Slot Str_Type_slots[] = {
|
static PyType_Slot Str_Type_slots[] = {
|
||||||
|
// slots array intentionally kept empty
|
||||||
{0, 0}, /* sentinel */
|
{0, 0}, /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -400,12 +424,32 @@ xx_modexec(PyObject *m)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static PyModuleDef_Slot xx_slots[] = {
|
static PyModuleDef_Slot xx_slots[] = {
|
||||||
|
|
||||||
|
/* exec function to initialize the module (called as part of import
|
||||||
|
* after the object was added to sys.modules)
|
||||||
|
*/
|
||||||
{Py_mod_exec, xx_modexec},
|
{Py_mod_exec, xx_modexec},
|
||||||
|
|
||||||
|
/* Signal that this module supports being loaded in multiple interpreters
|
||||||
|
* with separate GILs (global interpreter locks).
|
||||||
|
* See "Isolating Extension Modules" on how to prepare a module for this:
|
||||||
|
* https://docs.python.org/3/howto/isolating-extensions.html
|
||||||
|
*/
|
||||||
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
|
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
|
||||||
|
|
||||||
|
/* Signal that this module does not rely on the GIL for its own needs.
|
||||||
|
* Without this slot, free-threaded builds of CPython will enable
|
||||||
|
* the GIL when this module is loaded.
|
||||||
|
*/
|
||||||
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
||||||
|
|
||||||
{0, NULL}
|
{0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Module finalization: modules that hold references in their module state
|
||||||
|
// need to implement the fullowing GC hooks. They're similar to the ones for
|
||||||
|
// types (see "Xxo finalization").
|
||||||
|
|
||||||
static int
|
static int
|
||||||
xx_traverse(PyObject *module, visitproc visit, void *arg)
|
xx_traverse(PyObject *module, visitproc visit, void *arg)
|
||||||
{
|
{
|
||||||
@@ -444,7 +488,9 @@ static struct PyModuleDef xxmodule = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Export function for the module (*must* be called PyInit_xx) */
|
/* Export function for the module. *Must* be called PyInit_xx; usually it is
|
||||||
|
* the only non-`static` object in a module definition.
|
||||||
|
*/
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
PyMODINIT_FUNC
|
||||||
PyInit_xxlimited(void)
|
PyInit_xxlimited(void)
|
||||||
|
|||||||
Reference in New Issue
Block a user