LCOV - code coverage report
Current view: top level - Objects - structseq.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 224 294 76.2 %
Date: 2022-07-07 18:19:46 Functions: 15 18 83.3 %

          Line data    Source code
       1             : /* Implementation helper: a struct that looks like a tuple.
       2             :    See timemodule and posixmodule for example uses.
       3             : 
       4             :    The structseq helper is considered an internal CPython implementation
       5             :    detail.  Docs for modules using structseqs should call them
       6             :    "named tuples" (be sure to include a space between the two
       7             :    words and add a link back to the term in Docs/glossary.rst).
       8             : */
       9             : 
      10             : #include "Python.h"
      11             : #include "pycore_tuple.h"         // _PyTuple_FromArray()
      12             : #include "pycore_object.h"        // _PyObject_GC_TRACK()
      13             : #include "structmember.h"         // PyMemberDef
      14             : #include "pycore_structseq.h"     // PyStructSequence_InitType()
      15             : #include "pycore_initconfig.h"    // _PyStatus_OK()
      16             : 
      17             : static const char visible_length_key[] = "n_sequence_fields";
      18             : static const char real_length_key[] = "n_fields";
      19             : static const char unnamed_fields_key[] = "n_unnamed_fields";
      20             : static const char match_args_key[] = "__match_args__";
      21             : 
      22             : /* Fields with this name have only a field index, not a field name.
      23             :    They are only allowed for indices < n_visible_fields. */
      24             : const char * const PyStructSequence_UnnamedField = "unnamed field";
      25             : 
      26             : static Py_ssize_t
      27     4205860 : get_type_attr_as_size(PyTypeObject *tp, PyObject *name)
      28             : {
      29     4205860 :     PyObject *v = PyDict_GetItemWithError(tp->tp_dict, name);
      30     4205860 :     if (v == NULL && !PyErr_Occurred()) {
      31           0 :         PyErr_Format(PyExc_TypeError,
      32             :                      "Missed attribute '%U' of type %s",
      33             :                      name, tp->tp_name);
      34             :     }
      35     4205860 :     return PyLong_AsSsize_t(v);
      36             : }
      37             : 
      38             : #define VISIBLE_SIZE(op) Py_SIZE(op)
      39             : #define VISIBLE_SIZE_TP(tp) \
      40             :     get_type_attr_as_size(tp, &_Py_ID(n_sequence_fields))
      41             : #define REAL_SIZE_TP(tp) \
      42             :     get_type_attr_as_size(tp, &_Py_ID(n_fields))
      43             : #define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op))
      44             : 
      45             : #define UNNAMED_FIELDS_TP(tp) \
      46             :     get_type_attr_as_size(tp, &_Py_ID(n_unnamed_fields))
      47             : #define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op))
      48             : 
      49             : 
      50             : PyObject *
      51     1373430 : PyStructSequence_New(PyTypeObject *type)
      52             : {
      53             :     PyStructSequence *obj;
      54     1373430 :     Py_ssize_t size = REAL_SIZE_TP(type), i;
      55     1373430 :     if (size < 0) {
      56           0 :         return NULL;
      57             :     }
      58     1373430 :     Py_ssize_t vsize = VISIBLE_SIZE_TP(type);
      59     1373430 :     if (vsize < 0) {
      60           0 :         return NULL;
      61             :     }
      62             : 
      63     1373430 :     obj = PyObject_GC_NewVar(PyStructSequence, type, size);
      64     1373430 :     if (obj == NULL)
      65          59 :         return NULL;
      66             :     /* Hack the size of the variable object, so invisible fields don't appear
      67             :      to Python code. */
      68     1373370 :     Py_SET_SIZE(obj, vsize);
      69    26588900 :     for (i = 0; i < size; i++)
      70    25215600 :         obj->ob_item[i] = NULL;
      71             : 
      72     1373370 :     return (PyObject*)obj;
      73             : }
      74             : 
      75             : void
      76           0 : PyStructSequence_SetItem(PyObject* op, Py_ssize_t i, PyObject* v)
      77             : {
      78           0 :     PyStructSequence_SET_ITEM(op, i, v);
      79           0 : }
      80             : 
      81             : PyObject*
      82           0 : PyStructSequence_GetItem(PyObject* op, Py_ssize_t i)
      83             : {
      84           0 :     return PyStructSequence_GET_ITEM(op, i);
      85             : }
      86             : 
      87             : 
      88             : static int
      89         622 : structseq_traverse(PyStructSequence *obj, visitproc visit, void *arg)
      90             : {
      91         622 :     if (Py_TYPE(obj)->tp_flags & Py_TPFLAGS_HEAPTYPE) {
      92         622 :         Py_VISIT(Py_TYPE(obj));
      93             :     }
      94             :     Py_ssize_t i, size;
      95         622 :     size = REAL_SIZE(obj);
      96        4008 :     for (i = 0; i < size; ++i) {
      97        3386 :         Py_VISIT(obj->ob_item[i]);
      98             :     }
      99         622 :     return 0;
     100             : }
     101             : 
     102             : static void
     103     1373280 : structseq_dealloc(PyStructSequence *obj)
     104             : {
     105             :     Py_ssize_t i, size;
     106     1373280 :     PyObject_GC_UnTrack(obj);
     107             : 
     108     1373280 :     PyTypeObject *tp = Py_TYPE(obj);
     109     1373280 :     size = REAL_SIZE(obj);
     110    26588200 :     for (i = 0; i < size; ++i) {
     111    25214900 :         Py_XDECREF(obj->ob_item[i]);
     112             :     }
     113     1373280 :     PyObject_GC_Del(obj);
     114     1373280 :     if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) {
     115     1349190 :         Py_DECREF(tp);
     116             :     }
     117     1373280 : }
     118             : 
     119             : /*[clinic input]
     120             : class structseq "PyStructSequence *" "NULL"
     121             : [clinic start generated code]*/
     122             : /*[clinic end generated code: output=da39a3ee5e6b4b0d input=9d781c6922c77752]*/
     123             : 
     124             : #include "clinic/structseq.c.h"
     125             : 
     126             : /*[clinic input]
     127             : @classmethod
     128             : structseq.__new__ as structseq_new
     129             :     sequence as arg: object
     130             :     dict: object(c_default="NULL") = {}
     131             : [clinic start generated code]*/
     132             : 
     133             : static PyObject *
     134       28286 : structseq_new_impl(PyTypeObject *type, PyObject *arg, PyObject *dict)
     135             : /*[clinic end generated code: output=baa082e788b171da input=90532511101aa3fb]*/
     136             : {
     137             :     PyObject *ob;
     138       28286 :     PyStructSequence *res = NULL;
     139             :     Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;
     140             : 
     141       28286 :     min_len = VISIBLE_SIZE_TP(type);
     142       28286 :     if (min_len < 0) {
     143           0 :         return NULL;
     144             :     }
     145       28286 :     max_len = REAL_SIZE_TP(type);
     146       28286 :     if (max_len < 0) {
     147           0 :         return NULL;
     148             :     }
     149       28286 :     n_unnamed_fields = UNNAMED_FIELDS_TP(type);
     150       28286 :     if (n_unnamed_fields < 0) {
     151           0 :         return NULL;
     152             :     }
     153             : 
     154       28286 :     arg = PySequence_Fast(arg, "constructor requires a sequence");
     155             : 
     156       28286 :     if (!arg) {
     157           2 :         return NULL;
     158             :     }
     159             : 
     160       28284 :     if (dict && !PyDict_Check(dict)) {
     161           1 :         PyErr_Format(PyExc_TypeError,
     162             :                      "%.500s() takes a dict as second arg, if any",
     163             :                      type->tp_name);
     164           1 :         Py_DECREF(arg);
     165           1 :         return NULL;
     166             :     }
     167             : 
     168       28283 :     len = PySequence_Fast_GET_SIZE(arg);
     169       28283 :     if (min_len != max_len) {
     170        6905 :         if (len < min_len) {
     171           5 :             PyErr_Format(PyExc_TypeError,
     172             :                 "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
     173             :                 type->tp_name, min_len, len);
     174           5 :             Py_DECREF(arg);
     175           5 :             return NULL;
     176             :         }
     177             : 
     178        6900 :         if (len > max_len) {
     179           1 :             PyErr_Format(PyExc_TypeError,
     180             :                 "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
     181             :                 type->tp_name, max_len, len);
     182           1 :             Py_DECREF(arg);
     183           1 :             return NULL;
     184             :         }
     185             :     }
     186             :     else {
     187       21378 :         if (len != min_len) {
     188           0 :             PyErr_Format(PyExc_TypeError,
     189             :                          "%.500s() takes a %zd-sequence (%zd-sequence given)",
     190             :                          type->tp_name, min_len, len);
     191           0 :             Py_DECREF(arg);
     192           0 :             return NULL;
     193             :         }
     194             :     }
     195             : 
     196       28277 :     res = (PyStructSequence*) PyStructSequence_New(type);
     197       28277 :     if (res == NULL) {
     198           0 :         Py_DECREF(arg);
     199           0 :         return NULL;
     200             :     }
     201      137077 :     for (i = 0; i < len; ++i) {
     202      108800 :         PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
     203      108800 :         Py_INCREF(v);
     204      108800 :         res->ob_item[i] = v;
     205             :     }
     206       28277 :     Py_DECREF(arg);
     207       40785 :     for (; i < max_len; ++i) {
     208       12508 :         if (dict == NULL) {
     209       12044 :             ob = Py_None;
     210             :         }
     211             :         else {
     212         464 :             ob = _PyDict_GetItemStringWithError(dict,
     213         464 :                 type->tp_members[i-n_unnamed_fields].name);
     214         464 :             if (ob == NULL) {
     215           2 :                 if (PyErr_Occurred()) {
     216           0 :                     Py_DECREF(res);
     217           0 :                     return NULL;
     218             :                 }
     219           2 :                 ob = Py_None;
     220             :             }
     221             :         }
     222       12508 :         Py_INCREF(ob);
     223       12508 :         res->ob_item[i] = ob;
     224             :     }
     225             : 
     226       28277 :     _PyObject_GC_TRACK(res);
     227       28277 :     return (PyObject*) res;
     228             : }
     229             : 
     230             : 
     231             : static PyObject *
     232         230 : structseq_repr(PyStructSequence *obj)
     233             : {
     234         230 :     PyTypeObject *typ = Py_TYPE(obj);
     235             :     _PyUnicodeWriter writer;
     236             : 
     237             :     /* Write "typename(" */
     238         230 :     PyObject *type_name = PyUnicode_DecodeUTF8(typ->tp_name,
     239         230 :                                                strlen(typ->tp_name),
     240             :                                                NULL);
     241         230 :     if (type_name == NULL) {
     242           0 :         return NULL;
     243             :     }
     244             : 
     245         230 :     _PyUnicodeWriter_Init(&writer);
     246         230 :     writer.overallocate = 1;
     247             :     /* count 5 characters per item: "x=1, " */
     248         230 :     writer.min_length = (PyUnicode_GET_LENGTH(type_name) + 1
     249         230 :                          + VISIBLE_SIZE(obj) * 5 + 1);
     250             : 
     251         230 :     if (_PyUnicodeWriter_WriteStr(&writer, type_name) < 0) {
     252           0 :         Py_DECREF(type_name);
     253           0 :         goto error;
     254             :     }
     255         230 :     Py_DECREF(type_name);
     256             : 
     257         230 :     if (_PyUnicodeWriter_WriteChar(&writer, '(') < 0) {
     258           0 :         goto error;
     259             :     }
     260             : 
     261        2579 :     for (Py_ssize_t i=0; i < VISIBLE_SIZE(obj); i++) {
     262        2349 :         if (i > 0) {
     263             :             /* Write ", " */
     264        2119 :             if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) {
     265           0 :                 goto error;
     266             :             }
     267             :         }
     268             : 
     269             :         /* Write "name=repr" */
     270        2349 :         const char *name_utf8 = typ->tp_members[i].name;
     271        2349 :         if (name_utf8 == NULL) {
     272           0 :             PyErr_Format(PyExc_SystemError, "In structseq_repr(), member %zd name is NULL"
     273             :                          " for type %.500s", i, typ->tp_name);
     274           0 :             goto error;
     275             :         }
     276             : 
     277        2349 :         PyObject *name = PyUnicode_DecodeUTF8(name_utf8, strlen(name_utf8), NULL);
     278        2349 :         if (name == NULL) {
     279           0 :             goto error;
     280             :         }
     281        2349 :         if (_PyUnicodeWriter_WriteStr(&writer, name) < 0) {
     282           0 :             Py_DECREF(name);
     283           0 :             goto error;
     284             :         }
     285        2349 :         Py_DECREF(name);
     286             : 
     287        2349 :         if (_PyUnicodeWriter_WriteChar(&writer, '=') < 0) {
     288           0 :             goto error;
     289             :         }
     290             : 
     291        2349 :         PyObject *value = PyStructSequence_GET_ITEM(obj, i);
     292        2349 :         assert(value != NULL);
     293        2349 :         PyObject *repr = PyObject_Repr(value);
     294        2349 :         if (repr == NULL) {
     295           0 :             goto error;
     296             :         }
     297        2349 :         if (_PyUnicodeWriter_WriteStr(&writer, repr) < 0) {
     298           0 :             Py_DECREF(repr);
     299           0 :             goto error;
     300             :         }
     301        2349 :         Py_DECREF(repr);
     302             :     }
     303             : 
     304         230 :     if (_PyUnicodeWriter_WriteChar(&writer, ')') < 0) {
     305           0 :         goto error;
     306             :     }
     307             : 
     308         230 :     return _PyUnicodeWriter_Finish(&writer);
     309             : 
     310           0 : error:
     311           0 :     _PyUnicodeWriter_Dealloc(&writer);
     312           0 :     return NULL;
     313             : }
     314             : 
     315             : 
     316             : static PyObject *
     317         121 : structseq_reduce(PyStructSequence* self, PyObject *Py_UNUSED(ignored))
     318             : {
     319         121 :     PyObject* tup = NULL;
     320         121 :     PyObject* dict = NULL;
     321             :     PyObject* result;
     322             :     Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields, i;
     323             : 
     324         121 :     n_fields = REAL_SIZE(self);
     325         121 :     if (n_fields < 0) {
     326           0 :         return NULL;
     327             :     }
     328         121 :     n_visible_fields = VISIBLE_SIZE(self);
     329         121 :     n_unnamed_fields = UNNAMED_FIELDS(self);
     330         121 :     if (n_unnamed_fields < 0) {
     331           0 :         return NULL;
     332             :     }
     333         121 :     tup = _PyTuple_FromArray(self->ob_item, n_visible_fields);
     334         121 :     if (!tup)
     335           0 :         goto error;
     336             : 
     337         121 :     dict = PyDict_New();
     338         121 :     if (!dict)
     339           0 :         goto error;
     340             : 
     341         585 :     for (i = n_visible_fields; i < n_fields; i++) {
     342         464 :         const char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;
     343         464 :         if (PyDict_SetItemString(dict, n, self->ob_item[i]) < 0)
     344           0 :             goto error;
     345             :     }
     346             : 
     347         121 :     result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);
     348             : 
     349         121 :     Py_DECREF(tup);
     350         121 :     Py_DECREF(dict);
     351             : 
     352         121 :     return result;
     353             : 
     354           0 : error:
     355           0 :     Py_XDECREF(tup);
     356           0 :     Py_XDECREF(dict);
     357           0 :     return NULL;
     358             : }
     359             : 
     360             : static PyMethodDef structseq_methods[] = {
     361             :     {"__reduce__", (PyCFunction)structseq_reduce, METH_NOARGS, NULL},
     362             :     {NULL, NULL}
     363             : };
     364             : 
     365             : static Py_ssize_t
     366       55541 : count_members(PyStructSequence_Desc *desc, Py_ssize_t *n_unnamed_members) {
     367             :     Py_ssize_t i;
     368             : 
     369       55541 :     *n_unnamed_members = 0;
     370      442860 :     for (i = 0; desc->fields[i].name != NULL; ++i) {
     371      387319 :         if (desc->fields[i].name == PyStructSequence_UnnamedField) {
     372        9390 :             (*n_unnamed_members)++;
     373             :         }
     374             :     }
     375       55541 :     return i;
     376             : }
     377             : 
     378             : static int
     379       55541 : initialize_structseq_dict(PyStructSequence_Desc *desc, PyObject* dict,
     380             :                           Py_ssize_t n_members, Py_ssize_t n_unnamed_members) {
     381             :     PyObject *v;
     382             : 
     383             : #define SET_DICT_FROM_SIZE(key, value)                                         \
     384             :     do {                                                                       \
     385             :         v = PyLong_FromSsize_t(value);                                         \
     386             :         if (v == NULL) {                                                       \
     387             :             return -1;                                                         \
     388             :         }                                                                      \
     389             :         if (PyDict_SetItemString(dict, key, v) < 0) {                          \
     390             :             Py_DECREF(v);                                                      \
     391             :             return -1;                                                         \
     392             :         }                                                                      \
     393             :         Py_DECREF(v);                                                          \
     394             :     } while (0)
     395             : 
     396       55541 :     SET_DICT_FROM_SIZE(visible_length_key, desc->n_in_sequence);
     397       55541 :     SET_DICT_FROM_SIZE(real_length_key, n_members);
     398       55541 :     SET_DICT_FROM_SIZE(unnamed_fields_key, n_unnamed_members);
     399             : 
     400             :     // Prepare and set __match_args__
     401             :     Py_ssize_t i, k;
     402       55541 :     PyObject* keys = PyTuple_New(desc->n_in_sequence);
     403       55541 :     if (keys == NULL) {
     404           0 :         return -1;
     405             :     }
     406             : 
     407      405286 :     for (i = k = 0; i < desc->n_in_sequence; ++i) {
     408      349745 :         if (desc->fields[i].name == PyStructSequence_UnnamedField) {
     409        9390 :             continue;
     410             :         }
     411      340355 :         PyObject* new_member = PyUnicode_FromString(desc->fields[i].name);
     412      340355 :         if (new_member == NULL) {
     413           0 :             goto error;
     414             :         }
     415      340355 :         PyTuple_SET_ITEM(keys, k, new_member);
     416      340355 :         k++;
     417             :     }
     418             : 
     419       55541 :     if (_PyTuple_Resize(&keys, k) == -1) {
     420           0 :         goto error;
     421             :     }
     422             : 
     423       55541 :     if (PyDict_SetItemString(dict, match_args_key, keys) < 0) {
     424           0 :         goto error;
     425             :     }
     426             : 
     427       55541 :     Py_DECREF(keys);
     428       55541 :     return 0;
     429             : 
     430           0 : error:
     431           0 :     Py_DECREF(keys);
     432           0 :     return -1;
     433             : }
     434             : 
     435             : static void
     436       55541 : initialize_members(PyStructSequence_Desc *desc, PyMemberDef* members,
     437             :                    Py_ssize_t n_members) {
     438             :     Py_ssize_t i, k;
     439             : 
     440      442860 :     for (i = k = 0; i < n_members; ++i) {
     441      387319 :         if (desc->fields[i].name == PyStructSequence_UnnamedField) {
     442        9390 :             continue;
     443             :         }
     444             : 
     445             :         /* The names and docstrings in these MemberDefs are statically */
     446             :         /* allocated so it is expected that they'll outlive the MemberDef */
     447      377929 :         members[k].name = desc->fields[i].name;
     448      377929 :         members[k].type = T_OBJECT;
     449      377929 :         members[k].offset = offsetof(PyStructSequence, ob_item)
     450      377929 :           + i * sizeof(PyObject*);
     451      377929 :         members[k].flags = READONLY;
     452      377929 :         members[k].doc = desc->fields[i].doc;
     453      377929 :         k++;
     454             :     }
     455       55541 :     members[k].name = NULL;
     456       55541 : }
     457             : 
     458             : 
     459             : int
     460       23704 : _PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc,
     461             :                            unsigned long tp_flags)
     462             : {
     463             :     PyMemberDef *members;
     464             :     Py_ssize_t n_members, n_unnamed_members;
     465             : 
     466             : #ifdef Py_TRACE_REFS
     467             :     /* if the type object was chained, unchain it first
     468             :        before overwriting its storage */
     469             :     if (type->ob_base.ob_base._ob_next) {
     470             :         _Py_ForgetReference((PyObject *)type);
     471             :     }
     472             : #endif
     473             : 
     474             :     /* PyTypeObject has already been initialized */
     475       23704 :     if (Py_REFCNT(type) != 0) {
     476           0 :         PyErr_BadInternalCall();
     477           0 :         return -1;
     478             :     }
     479             : 
     480       23704 :     type->tp_name = desc->name;
     481       23704 :     type->tp_basicsize = sizeof(PyStructSequence) - sizeof(PyObject *);
     482       23704 :     type->tp_itemsize = sizeof(PyObject *);
     483       23704 :     type->tp_dealloc = (destructor)structseq_dealloc;
     484       23704 :     type->tp_repr = (reprfunc)structseq_repr;
     485       23704 :     type->tp_doc = desc->doc;
     486       23704 :     type->tp_base = &PyTuple_Type;
     487       23704 :     type->tp_methods = structseq_methods;
     488       23704 :     type->tp_new = structseq_new;
     489       23704 :     type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags;
     490       23704 :     type->tp_traverse = (traverseproc) structseq_traverse;
     491             : 
     492       23704 :     n_members = count_members(desc, &n_unnamed_members);
     493       23704 :     members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1);
     494       23704 :     if (members == NULL) {
     495           0 :         PyErr_NoMemory();
     496           0 :         return -1;
     497             :     }
     498       23704 :     initialize_members(desc, members, n_members);
     499       23704 :     type->tp_members = members;
     500             : 
     501       23704 :     if (PyType_Ready(type) < 0) {
     502           0 :         PyMem_Free(members);
     503           0 :         return -1;
     504             :     }
     505       23704 :     Py_INCREF(type);
     506             : 
     507       23704 :     if (initialize_structseq_dict(
     508             :             desc, type->tp_dict, n_members, n_unnamed_members) < 0) {
     509           0 :         PyMem_Free(members);
     510           0 :         Py_DECREF(type);
     511           0 :         return -1;
     512             :     }
     513             : 
     514       23704 :     return 0;
     515             : }
     516             : 
     517             : int
     518       17778 : PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
     519             : {
     520       17778 :     return _PyStructSequence_InitType(type, desc, 0);
     521             : }
     522             : 
     523             : void
     524           0 : PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
     525             : {
     526           0 :     (void)PyStructSequence_InitType2(type, desc);
     527           0 : }
     528             : 
     529             : 
     530             : void
     531       23608 : _PyStructSequence_FiniType(PyTypeObject *type)
     532             : {
     533             :     // Ensure that the type is initialized
     534       23608 :     assert(type->tp_name != NULL);
     535       23608 :     assert(type->tp_base == &PyTuple_Type);
     536             : 
     537             :     // Cannot delete a type if it still has subclasses
     538       23608 :     if (type->tp_subclasses != NULL) {
     539           0 :         return;
     540             :     }
     541             : 
     542             :     // Undo PyStructSequence_NewType()
     543       23608 :     type->tp_name = NULL;
     544       23608 :     PyMem_Free(type->tp_members);
     545             : 
     546       23608 :     _PyStaticType_Dealloc(type);
     547       23608 :     assert(Py_REFCNT(type) == 1);
     548             :     // Undo Py_INCREF(type) of _PyStructSequence_InitType().
     549             :     // Don't use Py_DECREF(): static type must not be deallocated
     550       23608 :     Py_SET_REFCNT(type, 0);
     551             : #ifdef Py_REF_DEBUG
     552       23608 :     _Py_RefTotal--;
     553             : #endif
     554             : 
     555             :     // Make sure that _PyStructSequence_InitType() will initialize
     556             :     // the type again
     557       23608 :     assert(Py_REFCNT(type) == 0);
     558       23608 :     assert(type->tp_name == NULL);
     559             : }
     560             : 
     561             : 
     562             : PyTypeObject *
     563       31837 : _PyStructSequence_NewType(PyStructSequence_Desc *desc, unsigned long tp_flags)
     564             : {
     565             :     PyMemberDef *members;
     566             :     PyTypeObject *type;
     567             :     PyType_Slot slots[8];
     568             :     PyType_Spec spec;
     569             :     Py_ssize_t n_members, n_unnamed_members;
     570             : 
     571             :     /* Initialize MemberDefs */
     572       31837 :     n_members = count_members(desc, &n_unnamed_members);
     573       31837 :     members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1);
     574       31837 :     if (members == NULL) {
     575           0 :         PyErr_NoMemory();
     576           0 :         return NULL;
     577             :     }
     578       31837 :     initialize_members(desc, members, n_members);
     579             : 
     580             :     /* Initialize Slots */
     581       31837 :     slots[0] = (PyType_Slot){Py_tp_dealloc, (destructor)structseq_dealloc};
     582       31837 :     slots[1] = (PyType_Slot){Py_tp_repr, (reprfunc)structseq_repr};
     583       31837 :     slots[2] = (PyType_Slot){Py_tp_doc, (void *)desc->doc};
     584       31837 :     slots[3] = (PyType_Slot){Py_tp_methods, structseq_methods};
     585       31837 :     slots[4] = (PyType_Slot){Py_tp_new, structseq_new};
     586       31837 :     slots[5] = (PyType_Slot){Py_tp_members, members};
     587       31837 :     slots[6] = (PyType_Slot){Py_tp_traverse, (traverseproc)structseq_traverse};
     588       31837 :     slots[7] = (PyType_Slot){0, 0};
     589             : 
     590             :     /* Initialize Spec */
     591             :     /* The name in this PyType_Spec is statically allocated so it is */
     592             :     /* expected that it'll outlive the PyType_Spec */
     593       31837 :     spec.name = desc->name;
     594       31837 :     spec.basicsize = sizeof(PyStructSequence) - sizeof(PyObject *);
     595       31837 :     spec.itemsize = sizeof(PyObject *);
     596       31837 :     spec.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags;
     597       31837 :     spec.slots = slots;
     598             : 
     599       31837 :     type = (PyTypeObject *)PyType_FromSpecWithBases(&spec, (PyObject *)&PyTuple_Type);
     600       31837 :     PyMem_Free(members);
     601       31837 :     if (type == NULL) {
     602           0 :         return NULL;
     603             :     }
     604             : 
     605       31837 :     if (initialize_structseq_dict(
     606             :             desc, type->tp_dict, n_members, n_unnamed_members) < 0) {
     607           0 :         Py_DECREF(type);
     608           0 :         return NULL;
     609             :     }
     610             : 
     611       31837 :     return type;
     612             : }
     613             : 
     614             : 
     615             : PyTypeObject *
     616       31834 : PyStructSequence_NewType(PyStructSequence_Desc *desc)
     617             : {
     618       31834 :     return _PyStructSequence_NewType(desc, 0);
     619             : }

Generated by: LCOV version 1.14