mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	gh-129675: Update documentation for tp_basicsize & tp_itemsize (#129850)
* Update documentation for tp_basicsize & tp_itemsize - Add alignment requirement - Mention that ob_size is unreliable if you don't control it - Add some links for context - basicsize should include the base type in generaly not just PyObject This adds a “by-the-way” link to `PyObject_New`, which shouldn't be used for GC types. In order to be comfortable linking to it, I also add a link to `PyObject_GC_New` from its docs. And the same for `*Var` variants, while I'm here. * Strongly suggest Py_SIZE & Py_SET_SIZE
This commit is contained in:
		
							parent
							
								
									faadb446d9
								
							
						
					
					
						commit
						ad0f618ab3
					
				
					 3 changed files with 81 additions and 28 deletions
				
			
		|  | @ -35,6 +35,10 @@ Allocating Objects on the Heap | |||
|    The size of the memory allocation is determined from the | ||||
|    :c:member:`~PyTypeObject.tp_basicsize` field of the type object. | ||||
| 
 | ||||
|    Note that this function is unsuitable if *typeobj* has | ||||
|    :c:macro:`Py_TPFLAGS_HAVE_GC` set. For such objects, | ||||
|    use :c:func:`PyObject_GC_New` instead. | ||||
| 
 | ||||
| 
 | ||||
| .. c:macro:: PyObject_NewVar(TYPE, typeobj, size) | ||||
| 
 | ||||
|  | @ -49,6 +53,10 @@ Allocating Objects on the Heap | |||
|    fields into the same allocation decreases the number of allocations, | ||||
|    improving the memory management efficiency. | ||||
| 
 | ||||
|    Note that this function is unsuitable if *typeobj* has | ||||
|    :c:macro:`Py_TPFLAGS_HAVE_GC` set. For such objects, | ||||
|    use :c:func:`PyObject_GC_NewVar` instead. | ||||
| 
 | ||||
| 
 | ||||
| .. c:function:: void PyObject_Del(void *op) | ||||
| 
 | ||||
|  |  | |||
|  | @ -456,6 +456,9 @@ The following functions and structs are used to create | |||
|       class need *in addition* to the superclass. | ||||
|       Use :c:func:`PyObject_GetTypeData` to get a pointer to subclass-specific | ||||
|       memory reserved this way. | ||||
|       For negative :c:member:`!basicsize`, Python will insert padding when | ||||
|       needed to meet :c:member:`~PyTypeObject.tp_basicsize`'s alignment | ||||
|       requirements. | ||||
| 
 | ||||
|       .. versionchanged:: 3.12 | ||||
| 
 | ||||
|  |  | |||
|  | @ -537,6 +537,9 @@ PyVarObject Slots | |||
|    initialized to zero. For :ref:`dynamically allocated type objects | ||||
|    <heap-types>`, this field has a special internal meaning. | ||||
| 
 | ||||
|    This field should be accessed using the :c:func:`Py_SIZE()` and | ||||
|    :c:func:`Py_SET_SIZE()` macros. | ||||
| 
 | ||||
|    **Inheritance:** | ||||
| 
 | ||||
|    This field is not inherited by subtypes. | ||||
|  | @ -587,47 +590,86 @@ and :c:data:`PyType_Type` effectively act as defaults.) | |||
| 
 | ||||
| 
 | ||||
| .. c:member:: Py_ssize_t PyTypeObject.tp_basicsize | ||||
|              Py_ssize_t PyTypeObject.tp_itemsize | ||||
|               Py_ssize_t PyTypeObject.tp_itemsize | ||||
| 
 | ||||
|    These fields allow calculating the size in bytes of instances of the type. | ||||
| 
 | ||||
|    There are two kinds of types: types with fixed-length instances have a zero | ||||
|    :c:member:`~PyTypeObject.tp_itemsize` field, types with variable-length instances have a non-zero | ||||
|    :c:member:`~PyTypeObject.tp_itemsize` field.  For a type with fixed-length instances, all | ||||
|    instances have the same size, given in :c:member:`~PyTypeObject.tp_basicsize`. | ||||
|    :c:member:`!tp_itemsize` field, types with variable-length instances have a non-zero | ||||
|    :c:member:`!tp_itemsize` field.  For a type with fixed-length instances, all | ||||
|    instances have the same size, given in :c:member:`!tp_basicsize`. | ||||
|    (Exceptions to this rule can be made using | ||||
|    :c:func:`PyUnstable_Object_GC_NewWithExtraData`.) | ||||
| 
 | ||||
|    For a type with variable-length instances, the instances must have an | ||||
|    :c:member:`~PyVarObject.ob_size` field, and the instance size is :c:member:`~PyTypeObject.tp_basicsize` plus N | ||||
|    times :c:member:`~PyTypeObject.tp_itemsize`, where N is the "length" of the object.  The value of | ||||
|    N is typically stored in the instance's :c:member:`~PyVarObject.ob_size` field.  There are | ||||
|    exceptions:  for example, ints use a negative :c:member:`~PyVarObject.ob_size` to indicate a | ||||
|    negative number, and N is ``abs(ob_size)`` there.  Also, the presence of an | ||||
|    :c:member:`~PyVarObject.ob_size` field in the instance layout doesn't mean that the instance | ||||
|    structure is variable-length (for example, the structure for the list type has | ||||
|    fixed-length instances, yet those instances have a meaningful :c:member:`~PyVarObject.ob_size` | ||||
|    field). | ||||
|    :c:member:`~PyVarObject.ob_size` field, and the instance size is | ||||
|    :c:member:`!tp_basicsize` plus N times :c:member:`!tp_itemsize`, | ||||
|    where N is the "length" of the object. | ||||
| 
 | ||||
|    The basic size includes the fields in the instance declared by the macro | ||||
|    :c:macro:`PyObject_HEAD` or :c:macro:`PyObject_VAR_HEAD` (whichever is used to | ||||
|    declare the instance struct) and this in turn includes the  :c:member:`~PyObject._ob_prev` and | ||||
|    :c:member:`~PyObject._ob_next` fields if they are present.  This means that the only correct | ||||
|    way to get an initializer for the :c:member:`~PyTypeObject.tp_basicsize` is to use the | ||||
|    Functions like :c:func:`PyObject_NewVar` will take the value of N as an | ||||
|    argument, and store in the instance's :c:member:`~PyVarObject.ob_size` field. | ||||
|    Note that the :c:member:`~PyVarObject.ob_size` field may later be used for | ||||
|    other purposes. For example, :py:type:`int` instances use the bits of | ||||
|    :c:member:`~PyVarObject.ob_size` in an implementation-defined | ||||
|    way; the underlying storage and its size should be acessed using | ||||
|    :c:func:`PyLong_Export`. | ||||
| 
 | ||||
|    .. note:: | ||||
| 
 | ||||
|       The :c:member:`~PyVarObject.ob_size` field should be accessed using | ||||
|       the :c:func:`Py_SIZE()` and :c:func:`Py_SET_SIZE()` macros. | ||||
| 
 | ||||
|    Also, the presence of an :c:member:`~PyVarObject.ob_size` field in the | ||||
|    instance layout doesn't mean that the instance structure is variable-length. | ||||
|    For example, the :py:type:`list` type has fixed-length instances, yet those | ||||
|    instances have a :c:member:`~PyVarObject.ob_size` field. | ||||
|    (As with :py:type:`int`, avoid reading lists' :c:member:`!ob_size` directly. | ||||
|    Call :c:func:`PyList_Size` instead.) | ||||
| 
 | ||||
|    The :c:member:`!tp_basicsize` includes size needed for data of the type's | ||||
|    :c:member:`~PyTypeObject.tp_base`, plus any extra data needed | ||||
|    by each instance. | ||||
| 
 | ||||
|    The  correct way to set :c:member:`!tp_basicsize` is to use the | ||||
|    ``sizeof`` operator on the struct used to declare the instance layout. | ||||
|    The basic size does not include the GC header size. | ||||
|    This struct must include the struct used to declare the base type. | ||||
|    In other words, :c:member:`!tp_basicsize` must be greater than or equal | ||||
|    to the base's :c:member:`!tp_basicsize`. | ||||
| 
 | ||||
|    A note about alignment: if the variable items require a particular alignment, | ||||
|    this should be taken care of by the value of :c:member:`~PyTypeObject.tp_basicsize`.  Example: | ||||
|    suppose a type implements an array of ``double``. :c:member:`~PyTypeObject.tp_itemsize` is | ||||
|    ``sizeof(double)``. It is the programmer's responsibility that | ||||
|    :c:member:`~PyTypeObject.tp_basicsize` is a multiple of ``sizeof(double)`` (assuming this is the | ||||
|    alignment requirement for ``double``). | ||||
|    Since every type is a subtype of :py:type:`object`, this struct must | ||||
|    include :c:type:`PyObject` or :c:type:`PyVarObject` (depending on | ||||
|    whether :c:member:`~PyVarObject.ob_size` should be included). These are | ||||
|    usually defined by the macro :c:macro:`PyObject_HEAD` or | ||||
|    :c:macro:`PyObject_VAR_HEAD`, respectively. | ||||
| 
 | ||||
|    For any type with variable-length instances, this field must not be ``NULL``. | ||||
|    The basic size does not include the GC header size, as that header is not | ||||
|    part of :c:macro:`PyObject_HEAD`. | ||||
| 
 | ||||
|    For cases where struct used to declare the base type is unknown, | ||||
|    see :c:member:`PyType_Spec.basicsize` and :c:func:`PyType_FromMetaclass`. | ||||
| 
 | ||||
|    Notes about alignment: | ||||
| 
 | ||||
|    - :c:member:`!tp_basicsize` must be a multiple of ``_Alignof(PyObject)``. | ||||
|      When using ``sizeof`` on a ``struct`` that includes | ||||
|      :c:macro:`PyObject_HEAD`, as recommended, the compiler ensures this. | ||||
|      When not using a C ``struct``, or when using compiler | ||||
|      extensions like ``__attribute__((packed))``, it is up to you. | ||||
|    - If the variable items require a particular alignment, | ||||
|      :c:member:`!tp_basicsize` and :c:member:`!tp_itemsize` must each be a | ||||
|      multiple of that alignment. | ||||
|      For example, if a type's variable part stores a ``double``, it is | ||||
|      your responsibility that both fields are a multiple of | ||||
|      ``_Alignof(double)``. | ||||
| 
 | ||||
|    **Inheritance:** | ||||
| 
 | ||||
|    These fields are inherited separately by subtypes.  If the base type has a | ||||
|    non-zero :c:member:`~PyTypeObject.tp_itemsize`, it is generally not safe to set | ||||
|    These fields are inherited separately by subtypes. | ||||
|    (That is, if the field is set to zero, :c:func:`PyType_Ready` will copy | ||||
|    the value from the base type, indicating that the instances do not | ||||
|    need additional storage.) | ||||
| 
 | ||||
|    If the base type has a non-zero :c:member:`~PyTypeObject.tp_itemsize`, it is generally not safe to set | ||||
|    :c:member:`~PyTypeObject.tp_itemsize` to a different non-zero value in a subtype (though this | ||||
|    depends on the implementation of the base type). | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Petr Viktorin
						Petr Viktorin