• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_initconfig.h"    // _PyStatus_OK()
12 #include "pycore_modsupport.h"    // _PyArg_NoPositional()
13 #include "pycore_object.h"        // _PyObject_GC_TRACK()
14 #include "pycore_structseq.h"     // PyStructSequence_InitType()
15 #include "pycore_tuple.h"         // _PyTuple_FromArray()
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
get_type_attr_as_size(PyTypeObject * tp,PyObject * name)27 get_type_attr_as_size(PyTypeObject *tp, PyObject *name)
28 {
29     PyObject *v = PyDict_GetItemWithError(_PyType_GetDict(tp), name);
30     if (v == NULL && !PyErr_Occurred()) {
31         PyErr_Format(PyExc_TypeError,
32                      "Missed attribute '%U' of type %s",
33                      name, tp->tp_name);
34         return -1;
35     }
36     return PyLong_AsSsize_t(v);
37 }
38 
39 #define VISIBLE_SIZE(op) Py_SIZE(op)
40 #define VISIBLE_SIZE_TP(tp) \
41     get_type_attr_as_size(tp, &_Py_ID(n_sequence_fields))
42 #define REAL_SIZE_TP(tp) \
43     get_type_attr_as_size(tp, &_Py_ID(n_fields))
44 #define REAL_SIZE(op) get_real_size((PyObject *)op)
45 
46 #define UNNAMED_FIELDS_TP(tp) \
47     get_type_attr_as_size(tp, &_Py_ID(n_unnamed_fields))
48 #define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op))
49 
50 static Py_ssize_t
get_real_size(PyObject * op)51 get_real_size(PyObject *op)
52 {
53     // Compute the real size from the visible size (i.e., Py_SIZE()) and the
54     // number of non-sequence fields accounted for in tp_basicsize.
55     Py_ssize_t hidden = Py_TYPE(op)->tp_basicsize - offsetof(PyStructSequence, ob_item);
56     return Py_SIZE(op) + hidden / sizeof(PyObject *);
57 }
58 
59 PyObject *
PyStructSequence_New(PyTypeObject * type)60 PyStructSequence_New(PyTypeObject *type)
61 {
62     PyStructSequence *obj;
63     Py_ssize_t size = REAL_SIZE_TP(type), i;
64     if (size < 0) {
65         return NULL;
66     }
67     Py_ssize_t vsize = VISIBLE_SIZE_TP(type);
68     if (vsize < 0) {
69         return NULL;
70     }
71 
72     obj = PyObject_GC_NewVar(PyStructSequence, type, size);
73     if (obj == NULL)
74         return NULL;
75     /* Hack the size of the variable object, so invisible fields don't appear
76      to Python code. */
77     Py_SET_SIZE(obj, vsize);
78     for (i = 0; i < size; i++)
79         obj->ob_item[i] = NULL;
80 
81     return (PyObject*)obj;
82 }
83 
84 void
PyStructSequence_SetItem(PyObject * op,Py_ssize_t index,PyObject * value)85 PyStructSequence_SetItem(PyObject *op, Py_ssize_t index, PyObject *value)
86 {
87     PyTupleObject *tuple = _PyTuple_CAST(op);
88     assert(0 <= index);
89 #ifndef NDEBUG
90     Py_ssize_t n_fields = REAL_SIZE(op);
91     assert(n_fields >= 0);
92     assert(index < n_fields);
93 #endif
94     tuple->ob_item[index] = value;
95 }
96 
97 PyObject*
PyStructSequence_GetItem(PyObject * op,Py_ssize_t index)98 PyStructSequence_GetItem(PyObject *op, Py_ssize_t index)
99 {
100     assert(0 <= index);
101 #ifndef NDEBUG
102     Py_ssize_t n_fields = REAL_SIZE(op);
103     assert(n_fields >= 0);
104     assert(index < n_fields);
105 #endif
106     return PyTuple_GET_ITEM(op, index);
107 }
108 
109 
110 static int
structseq_traverse(PyStructSequence * obj,visitproc visit,void * arg)111 structseq_traverse(PyStructSequence *obj, visitproc visit, void *arg)
112 {
113     if (Py_TYPE(obj)->tp_flags & Py_TPFLAGS_HEAPTYPE) {
114         Py_VISIT(Py_TYPE(obj));
115     }
116     Py_ssize_t i, size;
117     size = REAL_SIZE(obj);
118     for (i = 0; i < size; ++i) {
119         Py_VISIT(obj->ob_item[i]);
120     }
121     return 0;
122 }
123 
124 static void
structseq_dealloc(PyStructSequence * obj)125 structseq_dealloc(PyStructSequence *obj)
126 {
127     Py_ssize_t i, size;
128     PyObject_GC_UnTrack(obj);
129 
130     PyTypeObject *tp = Py_TYPE(obj);
131     // gh-122527: We can't use REAL_SIZE_TP() or any macros that access the
132     // type's dictionary here, because the dictionary may have already been
133     // cleared by the garbage collector.
134     size = REAL_SIZE(obj);
135     for (i = 0; i < size; ++i) {
136         Py_XDECREF(obj->ob_item[i]);
137     }
138     PyObject_GC_Del(obj);
139     if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) {
140         Py_DECREF(tp);
141     }
142 }
143 
144 /*[clinic input]
145 class structseq "PyStructSequence *" "NULL"
146 [clinic start generated code]*/
147 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=9d781c6922c77752]*/
148 
149 #include "clinic/structseq.c.h"
150 
151 /*[clinic input]
152 @classmethod
153 structseq.__new__ as structseq_new
154     sequence as arg: object
155     dict: object(c_default="NULL") = {}
156 [clinic start generated code]*/
157 
158 static PyObject *
structseq_new_impl(PyTypeObject * type,PyObject * arg,PyObject * dict)159 structseq_new_impl(PyTypeObject *type, PyObject *arg, PyObject *dict)
160 /*[clinic end generated code: output=baa082e788b171da input=90532511101aa3fb]*/
161 {
162     PyStructSequence *res = NULL;
163     Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;
164 
165     min_len = VISIBLE_SIZE_TP(type);
166     if (min_len < 0) {
167         return NULL;
168     }
169     max_len = REAL_SIZE_TP(type);
170     if (max_len < 0) {
171         return NULL;
172     }
173     n_unnamed_fields = UNNAMED_FIELDS_TP(type);
174     if (n_unnamed_fields < 0) {
175         return NULL;
176     }
177 
178     arg = PySequence_Fast(arg, "constructor requires a sequence");
179 
180     if (!arg) {
181         return NULL;
182     }
183 
184     if (dict && !PyDict_Check(dict)) {
185         PyErr_Format(PyExc_TypeError,
186                      "%.500s() takes a dict as second arg, if any",
187                      type->tp_name);
188         Py_DECREF(arg);
189         return NULL;
190     }
191 
192     len = PySequence_Fast_GET_SIZE(arg);
193     if (min_len != max_len) {
194         if (len < min_len) {
195             PyErr_Format(PyExc_TypeError,
196                 "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
197                 type->tp_name, min_len, len);
198             Py_DECREF(arg);
199             return NULL;
200         }
201 
202         if (len > max_len) {
203             PyErr_Format(PyExc_TypeError,
204                 "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
205                 type->tp_name, max_len, len);
206             Py_DECREF(arg);
207             return NULL;
208         }
209     }
210     else {
211         if (len != min_len) {
212             PyErr_Format(PyExc_TypeError,
213                          "%.500s() takes a %zd-sequence (%zd-sequence given)",
214                          type->tp_name, min_len, len);
215             Py_DECREF(arg);
216             return NULL;
217         }
218     }
219 
220     res = (PyStructSequence*) PyStructSequence_New(type);
221     if (res == NULL) {
222         Py_DECREF(arg);
223         return NULL;
224     }
225     for (i = 0; i < len; ++i) {
226         PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
227         res->ob_item[i] = Py_NewRef(v);
228     }
229     Py_DECREF(arg);
230     if (dict != NULL && PyDict_GET_SIZE(dict) > 0) {
231         Py_ssize_t n_found_keys = 0;
232         for (i = len; i < max_len; ++i) {
233             PyObject *ob = NULL;
234             const char *name = type->tp_members[i - n_unnamed_fields].name;
235             if (PyDict_GetItemStringRef(dict, name, &ob) < 0) {
236                 Py_DECREF(res);
237                 return NULL;
238             }
239             if (ob == NULL) {
240                 ob = Py_NewRef(Py_None);
241             }
242             else {
243                 ++n_found_keys;
244             }
245             res->ob_item[i] = ob;
246         }
247         if (PyDict_GET_SIZE(dict) > n_found_keys) {
248             PyErr_Format(PyExc_TypeError,
249                          "%.500s() got duplicate or unexpected field name(s)",
250                          type->tp_name);
251             Py_DECREF(res);
252             return NULL;
253         }
254     } else {
255         for (i = len; i < max_len; ++i) {
256             res->ob_item[i] = Py_NewRef(Py_None);
257         }
258     }
259 
260     _PyObject_GC_TRACK(res);
261     return (PyObject*) res;
262 }
263 
264 
265 static PyObject *
structseq_repr(PyStructSequence * obj)266 structseq_repr(PyStructSequence *obj)
267 {
268     PyTypeObject *typ = Py_TYPE(obj);
269     _PyUnicodeWriter writer;
270 
271     /* Write "typename(" */
272     PyObject *type_name = PyUnicode_DecodeUTF8(typ->tp_name,
273                                                strlen(typ->tp_name),
274                                                NULL);
275     if (type_name == NULL) {
276         return NULL;
277     }
278 
279     _PyUnicodeWriter_Init(&writer);
280     writer.overallocate = 1;
281     /* count 5 characters per item: "x=1, " */
282     writer.min_length = (PyUnicode_GET_LENGTH(type_name) + 1
283                          + VISIBLE_SIZE(obj) * 5 + 1);
284 
285     if (_PyUnicodeWriter_WriteStr(&writer, type_name) < 0) {
286         Py_DECREF(type_name);
287         goto error;
288     }
289     Py_DECREF(type_name);
290 
291     if (_PyUnicodeWriter_WriteChar(&writer, '(') < 0) {
292         goto error;
293     }
294 
295     for (Py_ssize_t i=0; i < VISIBLE_SIZE(obj); i++) {
296         if (i > 0) {
297             /* Write ", " */
298             if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) {
299                 goto error;
300             }
301         }
302 
303         /* Write "name=repr" */
304         const char *name_utf8 = typ->tp_members[i].name;
305         if (name_utf8 == NULL) {
306             PyErr_Format(PyExc_SystemError, "In structseq_repr(), member %zd name is NULL"
307                          " for type %.500s", i, typ->tp_name);
308             goto error;
309         }
310 
311         PyObject *name = PyUnicode_DecodeUTF8(name_utf8, strlen(name_utf8), NULL);
312         if (name == NULL) {
313             goto error;
314         }
315         if (_PyUnicodeWriter_WriteStr(&writer, name) < 0) {
316             Py_DECREF(name);
317             goto error;
318         }
319         Py_DECREF(name);
320 
321         if (_PyUnicodeWriter_WriteChar(&writer, '=') < 0) {
322             goto error;
323         }
324 
325         PyObject *value = PyStructSequence_GetItem((PyObject*)obj, i);
326         assert(value != NULL);
327         PyObject *repr = PyObject_Repr(value);
328         if (repr == NULL) {
329             goto error;
330         }
331         if (_PyUnicodeWriter_WriteStr(&writer, repr) < 0) {
332             Py_DECREF(repr);
333             goto error;
334         }
335         Py_DECREF(repr);
336     }
337 
338     if (_PyUnicodeWriter_WriteChar(&writer, ')') < 0) {
339         goto error;
340     }
341 
342     return _PyUnicodeWriter_Finish(&writer);
343 
344 error:
345     _PyUnicodeWriter_Dealloc(&writer);
346     return NULL;
347 }
348 
349 
350 static PyObject *
structseq_reduce(PyStructSequence * self,PyObject * Py_UNUSED (ignored))351 structseq_reduce(PyStructSequence* self, PyObject *Py_UNUSED(ignored))
352 {
353     PyObject* tup = NULL;
354     PyObject* dict = NULL;
355     PyObject* result;
356     Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields, i;
357 
358     n_fields = REAL_SIZE(self);
359     if (n_fields < 0) {
360         return NULL;
361     }
362     n_visible_fields = VISIBLE_SIZE(self);
363     n_unnamed_fields = UNNAMED_FIELDS(self);
364     if (n_unnamed_fields < 0) {
365         return NULL;
366     }
367     tup = _PyTuple_FromArray(self->ob_item, n_visible_fields);
368     if (!tup)
369         goto error;
370 
371     dict = PyDict_New();
372     if (!dict)
373         goto error;
374 
375     for (i = n_visible_fields; i < n_fields; i++) {
376         const char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;
377         if (PyDict_SetItemString(dict, n, self->ob_item[i]) < 0)
378             goto error;
379     }
380 
381     result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);
382 
383     Py_DECREF(tup);
384     Py_DECREF(dict);
385 
386     return result;
387 
388 error:
389     Py_XDECREF(tup);
390     Py_XDECREF(dict);
391     return NULL;
392 }
393 
394 
395 static PyObject *
structseq_replace(PyStructSequence * self,PyObject * args,PyObject * kwargs)396 structseq_replace(PyStructSequence *self, PyObject *args, PyObject *kwargs)
397 {
398     PyStructSequence *result = NULL;
399     Py_ssize_t n_fields, n_unnamed_fields, i;
400 
401     if (!_PyArg_NoPositional("__replace__", args)) {
402         return NULL;
403     }
404 
405     n_fields = REAL_SIZE(self);
406     if (n_fields < 0) {
407         return NULL;
408     }
409     n_unnamed_fields = UNNAMED_FIELDS(self);
410     if (n_unnamed_fields < 0) {
411         return NULL;
412     }
413     if (n_unnamed_fields > 0) {
414         PyErr_Format(PyExc_TypeError,
415                      "__replace__() is not supported for %.500s "
416                      "because it has unnamed field(s)",
417                      Py_TYPE(self)->tp_name);
418         return NULL;
419     }
420 
421     result = (PyStructSequence *) PyStructSequence_New(Py_TYPE(self));
422     if (!result) {
423         return NULL;
424     }
425 
426     if (kwargs != NULL) {
427         // We do not support types with unnamed fields, so we can iterate over
428         // i >= n_visible_fields case without slicing with (i - n_unnamed_fields).
429         for (i = 0; i < n_fields; ++i) {
430             PyObject *ob;
431             if (PyDict_PopString(kwargs, Py_TYPE(self)->tp_members[i].name,
432                                  &ob) < 0) {
433                 goto error;
434             }
435             if (ob == NULL) {
436                 ob = Py_NewRef(self->ob_item[i]);
437             }
438             result->ob_item[i] = ob;
439         }
440         // Check if there are any unexpected fields.
441         if (PyDict_GET_SIZE(kwargs) > 0) {
442             PyObject *names = PyDict_Keys(kwargs);
443             if (names) {
444                 PyErr_Format(PyExc_TypeError, "Got unexpected field name(s): %R", names);
445                 Py_DECREF(names);
446             }
447             goto error;
448         }
449     }
450     else
451     {
452         // Just create a copy of the original.
453         for (i = 0; i < n_fields; ++i) {
454             result->ob_item[i] = Py_NewRef(self->ob_item[i]);
455         }
456     }
457 
458     return (PyObject *)result;
459 
460 error:
461     Py_DECREF(result);
462     return NULL;
463 }
464 
465 static PyMethodDef structseq_methods[] = {
466     {"__reduce__", (PyCFunction)structseq_reduce, METH_NOARGS, NULL},
467     {"__replace__", _PyCFunction_CAST(structseq_replace), METH_VARARGS | METH_KEYWORDS,
468      PyDoc_STR("__replace__($self, /, **changes)\n--\n\n"
469         "Return a copy of the structure with new values for the specified fields.")},
470     {NULL, NULL}  // sentinel
471 };
472 
473 static Py_ssize_t
count_members(PyStructSequence_Desc * desc,Py_ssize_t * n_unnamed_members)474 count_members(PyStructSequence_Desc *desc, Py_ssize_t *n_unnamed_members) {
475     Py_ssize_t i;
476 
477     *n_unnamed_members = 0;
478     for (i = 0; desc->fields[i].name != NULL; ++i) {
479         if (desc->fields[i].name == PyStructSequence_UnnamedField) {
480             (*n_unnamed_members)++;
481         }
482     }
483     return i;
484 }
485 
486 static int
initialize_structseq_dict(PyStructSequence_Desc * desc,PyObject * dict,Py_ssize_t n_members,Py_ssize_t n_unnamed_members)487 initialize_structseq_dict(PyStructSequence_Desc *desc, PyObject* dict,
488                           Py_ssize_t n_members, Py_ssize_t n_unnamed_members) {
489     PyObject *v;
490 
491 #define SET_DICT_FROM_SIZE(key, value)                                         \
492     do {                                                                       \
493         v = PyLong_FromSsize_t(value);                                         \
494         if (v == NULL) {                                                       \
495             return -1;                                                         \
496         }                                                                      \
497         if (PyDict_SetItemString(dict, key, v) < 0) {                          \
498             Py_DECREF(v);                                                      \
499             return -1;                                                         \
500         }                                                                      \
501         Py_DECREF(v);                                                          \
502     } while (0)
503 
504     SET_DICT_FROM_SIZE(visible_length_key, desc->n_in_sequence);
505     SET_DICT_FROM_SIZE(real_length_key, n_members);
506     SET_DICT_FROM_SIZE(unnamed_fields_key, n_unnamed_members);
507 
508     // Prepare and set __match_args__
509     Py_ssize_t i, k;
510     PyObject* keys = PyTuple_New(desc->n_in_sequence);
511     if (keys == NULL) {
512         return -1;
513     }
514 
515     for (i = k = 0; i < desc->n_in_sequence; ++i) {
516         if (desc->fields[i].name == PyStructSequence_UnnamedField) {
517             continue;
518         }
519         PyObject* new_member = PyUnicode_FromString(desc->fields[i].name);
520         if (new_member == NULL) {
521             goto error;
522         }
523         PyTuple_SET_ITEM(keys, k, new_member);
524         k++;
525     }
526 
527     if (_PyTuple_Resize(&keys, k) == -1) {
528         goto error;
529     }
530 
531     if (PyDict_SetItemString(dict, match_args_key, keys) < 0) {
532         goto error;
533     }
534 
535     Py_DECREF(keys);
536     return 0;
537 
538 error:
539     Py_DECREF(keys);
540     return -1;
541 }
542 
543 static PyMemberDef *
initialize_members(PyStructSequence_Desc * desc,Py_ssize_t n_members,Py_ssize_t n_unnamed_members)544 initialize_members(PyStructSequence_Desc *desc,
545                    Py_ssize_t n_members, Py_ssize_t n_unnamed_members)
546 {
547     PyMemberDef *members;
548 
549     members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1);
550     if (members == NULL) {
551         PyErr_NoMemory();
552         return NULL;
553     }
554 
555     Py_ssize_t i, k;
556     for (i = k = 0; i < n_members; ++i) {
557         if (desc->fields[i].name == PyStructSequence_UnnamedField) {
558             continue;
559         }
560 
561         /* The names and docstrings in these MemberDefs are statically */
562         /* allocated so it is expected that they'll outlive the MemberDef */
563         members[k].name = desc->fields[i].name;
564         members[k].type = _Py_T_OBJECT;
565         members[k].offset = offsetof(PyStructSequence, ob_item)
566           + i * sizeof(PyObject*);
567         members[k].flags = Py_READONLY;
568         members[k].doc = desc->fields[i].doc;
569         k++;
570     }
571     members[k].name = NULL;
572 
573     return members;
574 }
575 
576 
577 static void
initialize_static_fields(PyTypeObject * type,PyStructSequence_Desc * desc,PyMemberDef * tp_members,Py_ssize_t n_members,unsigned long tp_flags)578 initialize_static_fields(PyTypeObject *type, PyStructSequence_Desc *desc,
579                          PyMemberDef *tp_members, Py_ssize_t n_members,
580                          unsigned long tp_flags)
581 {
582     type->tp_name = desc->name;
583     // Account for hidden members in tp_basicsize because they are not
584     // included in the variable size.
585     Py_ssize_t n_hidden = n_members - desc->n_in_sequence;
586     type->tp_basicsize = sizeof(PyStructSequence) + (n_hidden - 1) * sizeof(PyObject *);
587     type->tp_itemsize = sizeof(PyObject *);
588     type->tp_dealloc = (destructor)structseq_dealloc;
589     type->tp_repr = (reprfunc)structseq_repr;
590     type->tp_doc = desc->doc;
591     type->tp_base = &PyTuple_Type;
592     type->tp_methods = structseq_methods;
593     type->tp_new = structseq_new;
594     type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags;
595     type->tp_traverse = (traverseproc) structseq_traverse;
596     type->tp_members = tp_members;
597 }
598 
599 static int
initialize_static_type(PyTypeObject * type,PyStructSequence_Desc * desc,Py_ssize_t n_members,Py_ssize_t n_unnamed_members)600 initialize_static_type(PyTypeObject *type, PyStructSequence_Desc *desc,
601                        Py_ssize_t n_members, Py_ssize_t n_unnamed_members) {
602     /* initialize_static_fields() should have been called already. */
603     if (PyType_Ready(type) < 0) {
604         return -1;
605     }
606     Py_INCREF(type);
607 
608     if (initialize_structseq_dict(
609             desc, _PyType_GetDict(type), n_members, n_unnamed_members) < 0) {
610         Py_DECREF(type);
611         return -1;
612     }
613 
614     return 0;
615 }
616 
617 int
_PyStructSequence_InitBuiltinWithFlags(PyInterpreterState * interp,PyTypeObject * type,PyStructSequence_Desc * desc,unsigned long tp_flags)618 _PyStructSequence_InitBuiltinWithFlags(PyInterpreterState *interp,
619                                        PyTypeObject *type,
620                                        PyStructSequence_Desc *desc,
621                                        unsigned long tp_flags)
622 {
623     if (Py_TYPE(type) == NULL) {
624         Py_SET_TYPE(type, &PyType_Type);
625     }
626     Py_ssize_t n_unnamed_members;
627     Py_ssize_t n_members = count_members(desc, &n_unnamed_members);
628     PyMemberDef *members = NULL;
629 
630     if ((type->tp_flags & Py_TPFLAGS_READY) == 0) {
631         assert(type->tp_name == NULL);
632         assert(type->tp_members == NULL);
633         assert(type->tp_base == NULL);
634 
635         members = initialize_members(desc, n_members, n_unnamed_members);
636         if (members == NULL) {
637             goto error;
638         }
639         initialize_static_fields(type, desc, members, n_members, tp_flags);
640 
641         _Py_SetImmortal((PyObject *)type);
642     }
643 #ifndef NDEBUG
644     else {
645         // Ensure that the type was initialized.
646         assert(type->tp_name != NULL);
647         assert(type->tp_members != NULL);
648         assert(type->tp_base == &PyTuple_Type);
649         assert((type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN));
650         assert(_Py_IsImmortal(type));
651     }
652 #endif
653 
654     if (_PyStaticType_InitBuiltin(interp, type) < 0) {
655         PyErr_Format(PyExc_RuntimeError,
656                      "Can't initialize builtin type %s",
657                      desc->name);
658         goto error;
659     }
660 
661     if (initialize_structseq_dict(
662             desc, _PyType_GetDict(type), n_members, n_unnamed_members) < 0)
663     {
664         goto error;
665     }
666 
667     return 0;
668 
669 error:
670     if (members != NULL) {
671         PyMem_Free(members);
672     }
673     return -1;
674 }
675 
676 int
PyStructSequence_InitType2(PyTypeObject * type,PyStructSequence_Desc * desc)677 PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
678 {
679     PyMemberDef *members;
680     Py_ssize_t n_members, n_unnamed_members;
681 
682 #ifdef Py_TRACE_REFS
683     /* if the type object was traced, remove it first
684        before overwriting its storage */
685     PyInterpreterState *interp = _PyInterpreterState_GET();
686     if (_PyRefchain_IsTraced(interp, (PyObject *)type)) {
687         _Py_ForgetReference((PyObject *)type);
688     }
689 #endif
690 
691     /* PyTypeObject has already been initialized */
692     if (Py_REFCNT(type) != 0) {
693         PyErr_BadInternalCall();
694         return -1;
695     }
696 
697     n_members = count_members(desc, &n_unnamed_members);
698     members = initialize_members(desc, n_members, n_unnamed_members);
699     if (members == NULL) {
700         return -1;
701     }
702     initialize_static_fields(type, desc, members, n_members, 0);
703     if (initialize_static_type(type, desc, n_members, n_unnamed_members) < 0) {
704         PyMem_Free(members);
705         return -1;
706     }
707     return 0;
708 }
709 
710 void
PyStructSequence_InitType(PyTypeObject * type,PyStructSequence_Desc * desc)711 PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
712 {
713     (void)PyStructSequence_InitType2(type, desc);
714 }
715 
716 
717 /* This is exposed in the internal API, not the public API.
718    It is only called on builtin static types, which are all
719    initialized via _PyStructSequence_InitBuiltinWithFlags(). */
720 
721 void
_PyStructSequence_FiniBuiltin(PyInterpreterState * interp,PyTypeObject * type)722 _PyStructSequence_FiniBuiltin(PyInterpreterState *interp, PyTypeObject *type)
723 {
724     // Ensure that the type is initialized
725     assert(type->tp_name != NULL);
726     assert(type->tp_base == &PyTuple_Type);
727     assert((type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN));
728     assert(_Py_IsImmortalLoose(type));
729 
730     // Cannot delete a type if it still has subclasses
731     if (_PyType_HasSubclasses(type)) {
732         // XXX Shouldn't this be an error?
733         return;
734     }
735 
736     _PyStaticType_FiniBuiltin(interp, type);
737 
738     if (_Py_IsMainInterpreter(interp)) {
739         // Undo _PyStructSequence_InitBuiltinWithFlags().
740         type->tp_name = NULL;
741         PyMem_Free(type->tp_members);
742         type->tp_members = NULL;
743         type->tp_base = NULL;
744     }
745 }
746 
747 
748 PyTypeObject *
_PyStructSequence_NewType(PyStructSequence_Desc * desc,unsigned long tp_flags)749 _PyStructSequence_NewType(PyStructSequence_Desc *desc, unsigned long tp_flags)
750 {
751     PyMemberDef *members;
752     PyTypeObject *type;
753     PyType_Slot slots[8];
754     PyType_Spec spec;
755     Py_ssize_t n_members, n_unnamed_members;
756 
757     /* Initialize MemberDefs */
758     n_members = count_members(desc, &n_unnamed_members);
759     members = initialize_members(desc, n_members, n_unnamed_members);
760     if (members == NULL) {
761         return NULL;
762     }
763 
764     /* Initialize Slots */
765     slots[0] = (PyType_Slot){Py_tp_dealloc, (destructor)structseq_dealloc};
766     slots[1] = (PyType_Slot){Py_tp_repr, (reprfunc)structseq_repr};
767     slots[2] = (PyType_Slot){Py_tp_doc, (void *)desc->doc};
768     slots[3] = (PyType_Slot){Py_tp_methods, structseq_methods};
769     slots[4] = (PyType_Slot){Py_tp_new, structseq_new};
770     slots[5] = (PyType_Slot){Py_tp_members, members};
771     slots[6] = (PyType_Slot){Py_tp_traverse, (traverseproc)structseq_traverse};
772     slots[7] = (PyType_Slot){0, 0};
773 
774     /* Initialize Spec */
775     /* The name in this PyType_Spec is statically allocated so it is */
776     /* expected that it'll outlive the PyType_Spec */
777     spec.name = desc->name;
778     Py_ssize_t hidden = n_members - desc->n_in_sequence;
779     spec.basicsize = (int)(sizeof(PyStructSequence) + (hidden - 1) * sizeof(PyObject *));
780     spec.itemsize = sizeof(PyObject *);
781     spec.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags;
782     spec.slots = slots;
783 
784     type = (PyTypeObject *)PyType_FromSpecWithBases(&spec, (PyObject *)&PyTuple_Type);
785     PyMem_Free(members);
786     if (type == NULL) {
787         return NULL;
788     }
789 
790     if (initialize_structseq_dict(
791             desc, _PyType_GetDict(type), n_members, n_unnamed_members) < 0) {
792         Py_DECREF(type);
793         return NULL;
794     }
795 
796     return type;
797 }
798 
799 
800 PyTypeObject *
PyStructSequence_NewType(PyStructSequence_Desc * desc)801 PyStructSequence_NewType(PyStructSequence_Desc *desc)
802 {
803     return _PyStructSequence_NewType(desc, 0);
804 }
805