gh-124153: Implement PyType_GetBaseByToken() and Py_tp_token slot (GH-124163)

This commit is contained in:
neonene 2024-09-18 16:18:19 +09:00 committed by GitHub
parent 79a7410236
commit 646f16bdee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 443 additions and 13 deletions

View file

@ -264,6 +264,24 @@ Type Objects
.. versionadded:: 3.11
.. c:function:: int PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
Find the first superclass in *type*'s :term:`method resolution order` whose
:c:macro:`Py_tp_token` token is equal to the given one.
* If found, set *\*result* to a new :term:`strong reference`
to it and return ``1``.
* If not found, set *\*result* to ``NULL`` and return ``0``.
* On error, set *\*result* to ``NULL`` and return ``-1`` with an
exception set.
The *result* argument may be ``NULL``, in which case *\*result* is not set.
Use this if you need only the return value.
The *token* argument may not be ``NULL``.
.. versionadded:: 3.14
.. c:function:: int PyUnstable_Type_AssignVersionTag(PyTypeObject *type)
Attempt to assign a version tag to the given type.
@ -488,6 +506,11 @@ The following functions and structs are used to create
* ``Py_nb_add`` to set :c:member:`PyNumberMethods.nb_add`
* ``Py_sq_length`` to set :c:member:`PySequenceMethods.sq_length`
An additional slot is supported that does not correspond to a
:c:type:`!PyTypeObject` struct field:
* :c:data:`Py_tp_token`
The following “offset” fields cannot be set using :c:type:`PyType_Slot`:
* :c:member:`~PyTypeObject.tp_weaklistoffset`
@ -538,4 +561,47 @@ The following functions and structs are used to create
The desired value of the slot. In most cases, this is a pointer
to a function.
Slots other than ``Py_tp_doc`` may not be ``NULL``.
*pfunc* values may not be ``NULL``, except for the following slots:
* ``Py_tp_doc``
* :c:data:`Py_tp_token` (for clarity, prefer :c:data:`Py_TP_USE_SPEC`
rather than ``NULL``)
.. c:macro:: Py_tp_token
A :c:member:`~PyType_Slot.slot` that records a static memory layout ID
for a class.
If the :c:type:`PyType_Spec` of the class is statically
allocated, the token can be set to the spec using the special value
:c:data:`Py_TP_USE_SPEC`:
.. code-block:: c
static PyType_Slot foo_slots[] = {
{Py_tp_token, Py_TP_USE_SPEC},
It can also be set to an arbitrary pointer, but you must ensure that:
* The pointer outlives the class, so it's not reused for something else
while the class exists.
* It "belongs" to the extension module where the class lives, so it will not
clash with other extensions.
Use :c:func:`PyType_GetBaseByToken` to check if a class's superclass has
a given token -- that is, check whether the memory layout is compatible.
To get the token for a given class (without considering superclasses),
use :c:func:`PyType_GetSlot` with ``Py_tp_token``.
.. versionadded:: 3.14
.. c:namespace:: NULL
.. c:macro:: Py_TP_USE_SPEC
Used as a value with :c:data:`Py_tp_token` to set the token to the
class's :c:type:`PyType_Spec`.
Expands to ``NULL``.
.. versionadded:: 3.14