Branch data 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 : 3948124 : get_type_attr_as_size(PyTypeObject *tp, PyObject *name)
28 : : {
29 : 3948124 : PyObject *v = PyDict_GetItemWithError(tp->tp_dict, name);
30 [ - + - - ]: 3948124 : 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 : 3948124 : 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 : 1286654 : PyStructSequence_New(PyTypeObject *type)
52 : : {
53 : : PyStructSequence *obj;
54 : 1286654 : Py_ssize_t size = REAL_SIZE_TP(type), i;
55 [ - + ]: 1286654 : if (size < 0) {
56 : 0 : return NULL;
57 : : }
58 : 1286654 : Py_ssize_t vsize = VISIBLE_SIZE_TP(type);
59 [ - + ]: 1286654 : if (vsize < 0) {
60 : 0 : return NULL;
61 : : }
62 : :
63 : 1286654 : obj = PyObject_GC_NewVar(PyStructSequence, type, size);
64 [ + + ]: 1286654 : 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 : 1286595 : Py_SET_SIZE(obj, vsize);
69 [ + + ]: 24835109 : for (i = 0; i < size; i++)
70 : 23548514 : obj->ob_item[i] = NULL;
71 : :
72 : 1286595 : 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 : 1286511 : structseq_dealloc(PyStructSequence *obj)
104 : : {
105 : : Py_ssize_t i, size;
106 : 1286511 : PyObject_GC_UnTrack(obj);
107 : :
108 : 1286511 : PyTypeObject *tp = Py_TYPE(obj);
109 : 1286511 : size = REAL_SIZE(obj);
110 [ + + ]: 24834314 : for (i = 0; i < size; ++i) {
111 : 23547803 : Py_XDECREF(obj->ob_item[i]);
112 : : }
113 : 1286511 : PyObject_GC_Del(obj);
114 [ + + ]: 1286511 : if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) {
115 : 1262476 : Py_DECREF(tp);
116 : : }
117 : 1286511 : }
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 : 29147 : structseq_new_impl(PyTypeObject *type, PyObject *arg, PyObject *dict)
135 : : /*[clinic end generated code: output=baa082e788b171da input=90532511101aa3fb]*/
136 : : {
137 : : PyObject *ob;
138 : 29147 : PyStructSequence *res = NULL;
139 : : Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;
140 : :
141 : 29147 : min_len = VISIBLE_SIZE_TP(type);
142 [ - + ]: 29147 : if (min_len < 0) {
143 : 0 : return NULL;
144 : : }
145 : 29147 : max_len = REAL_SIZE_TP(type);
146 [ - + ]: 29147 : if (max_len < 0) {
147 : 0 : return NULL;
148 : : }
149 : 29147 : n_unnamed_fields = UNNAMED_FIELDS_TP(type);
150 [ - + ]: 29147 : if (n_unnamed_fields < 0) {
151 : 0 : return NULL;
152 : : }
153 : :
154 : 29147 : arg = PySequence_Fast(arg, "constructor requires a sequence");
155 : :
156 [ + + ]: 29147 : if (!arg) {
157 : 2 : return NULL;
158 : : }
159 : :
160 [ + + + + ]: 29145 : 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 [ + + ]: 29144 : len = PySequence_Fast_GET_SIZE(arg);
169 [ + + ]: 29144 : if (min_len != max_len) {
170 [ + + ]: 7048 : 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 [ + + ]: 7043 : 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 [ - + ]: 22096 : 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 : 29138 : res = (PyStructSequence*) PyStructSequence_New(type);
197 [ - + ]: 29138 : if (res == NULL) {
198 : 0 : Py_DECREF(arg);
199 : 0 : return NULL;
200 : : }
201 [ + + ]: 140673 : for (i = 0; i < len; ++i) {
202 [ + + ]: 111535 : PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
203 : 111535 : Py_INCREF(v);
204 : 111535 : res->ob_item[i] = v;
205 : : }
206 : 29138 : Py_DECREF(arg);
207 [ + + ]: 41952 : for (; i < max_len; ++i) {
208 [ + + ]: 12814 : if (dict == NULL) {
209 : 12350 : 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 : 12814 : Py_INCREF(ob);
223 : 12814 : res->ob_item[i] = ob;
224 : : }
225 : :
226 : 29138 : _PyObject_GC_TRACK(res);
227 : 29138 : 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 : : 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 : 55624 : count_members(PyStructSequence_Desc *desc, Py_ssize_t *n_unnamed_members) {
367 : : Py_ssize_t i;
368 : :
369 : 55624 : *n_unnamed_members = 0;
370 [ + + ]: 443491 : for (i = 0; desc->fields[i].name != NULL; ++i) {
371 [ + + ]: 387867 : if (desc->fields[i].name == PyStructSequence_UnnamedField) {
372 : 9405 : (*n_unnamed_members)++;
373 : : }
374 : : }
375 : 55624 : return i;
376 : : }
377 : :
378 : : static int
379 : 55624 : 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 [ - + - + ]: 55624 : SET_DICT_FROM_SIZE(visible_length_key, desc->n_in_sequence);
397 [ - + - + ]: 55624 : SET_DICT_FROM_SIZE(real_length_key, n_members);
398 [ - + - + ]: 55624 : SET_DICT_FROM_SIZE(unnamed_fields_key, n_unnamed_members);
399 : :
400 : : // Prepare and set __match_args__
401 : : Py_ssize_t i, k;
402 : 55624 : PyObject* keys = PyTuple_New(desc->n_in_sequence);
403 [ - + ]: 55624 : if (keys == NULL) {
404 : 0 : return -1;
405 : : }
406 : :
407 [ + + ]: 405857 : for (i = k = 0; i < desc->n_in_sequence; ++i) {
408 [ + + ]: 350233 : if (desc->fields[i].name == PyStructSequence_UnnamedField) {
409 : 9405 : continue;
410 : : }
411 : 340828 : PyObject* new_member = PyUnicode_FromString(desc->fields[i].name);
412 [ - + ]: 340828 : if (new_member == NULL) {
413 : 0 : goto error;
414 : : }
415 : 340828 : PyTuple_SET_ITEM(keys, k, new_member);
416 : 340828 : k++;
417 : : }
418 : :
419 [ - + ]: 55624 : if (_PyTuple_Resize(&keys, k) == -1) {
420 : 0 : goto error;
421 : : }
422 : :
423 [ - + ]: 55624 : if (PyDict_SetItemString(dict, match_args_key, keys) < 0) {
424 : 0 : goto error;
425 : : }
426 : :
427 : 55624 : Py_DECREF(keys);
428 : 55624 : return 0;
429 : :
430 : 0 : error:
431 : 0 : Py_DECREF(keys);
432 : 0 : return -1;
433 : : }
434 : :
435 : : static void
436 : 55624 : initialize_members(PyStructSequence_Desc *desc, PyMemberDef* members,
437 : : Py_ssize_t n_members) {
438 : : Py_ssize_t i, k;
439 : :
440 [ + + ]: 443491 : for (i = k = 0; i < n_members; ++i) {
441 [ + + ]: 387867 : if (desc->fields[i].name == PyStructSequence_UnnamedField) {
442 : 9405 : 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 : 378462 : members[k].name = desc->fields[i].name;
448 : 378462 : members[k].type = T_OBJECT;
449 : 378462 : members[k].offset = offsetof(PyStructSequence, ob_item)
450 : 378462 : + i * sizeof(PyObject*);
451 : 378462 : members[k].flags = READONLY;
452 : 378462 : members[k].doc = desc->fields[i].doc;
453 : 378462 : k++;
454 : : }
455 : 55624 : members[k].name = NULL;
456 : 55624 : }
457 : :
458 : :
459 : : int
460 : 23736 : _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 [ - + ]: 23736 : if (Py_REFCNT(type) != 0) {
476 : 0 : PyErr_BadInternalCall();
477 : 0 : return -1;
478 : : }
479 : :
480 : 23736 : type->tp_name = desc->name;
481 : 23736 : type->tp_basicsize = sizeof(PyStructSequence) - sizeof(PyObject *);
482 : 23736 : type->tp_itemsize = sizeof(PyObject *);
483 : 23736 : type->tp_dealloc = (destructor)structseq_dealloc;
484 : 23736 : type->tp_repr = (reprfunc)structseq_repr;
485 : 23736 : type->tp_doc = desc->doc;
486 : 23736 : type->tp_base = &PyTuple_Type;
487 : 23736 : type->tp_methods = structseq_methods;
488 : 23736 : type->tp_new = structseq_new;
489 : 23736 : type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags;
490 : 23736 : type->tp_traverse = (traverseproc) structseq_traverse;
491 : :
492 : 23736 : n_members = count_members(desc, &n_unnamed_members);
493 [ + - ]: 23736 : members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1);
494 [ - + ]: 23736 : if (members == NULL) {
495 : : PyErr_NoMemory();
496 : 0 : return -1;
497 : : }
498 : 23736 : initialize_members(desc, members, n_members);
499 : 23736 : type->tp_members = members;
500 : :
501 [ - + ]: 23736 : if (PyType_Ready(type) < 0) {
502 : 0 : PyMem_Free(members);
503 : 0 : return -1;
504 : : }
505 : 23736 : Py_INCREF(type);
506 : :
507 [ - + ]: 23736 : 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 : 23736 : return 0;
515 : : }
516 : :
517 : : int
518 : 17802 : PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
519 : : {
520 : 17802 : 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 : 23648 : _PyStructSequence_FiniType(PyTypeObject *type)
532 : : {
533 : : // Ensure that the type is initialized
534 : : assert(type->tp_name != NULL);
535 : : assert(type->tp_base == &PyTuple_Type);
536 : :
537 : : // Cannot delete a type if it still has subclasses
538 [ - + ]: 23648 : if (type->tp_subclasses != NULL) {
539 : 0 : return;
540 : : }
541 : :
542 : : // Undo PyStructSequence_NewType()
543 : 23648 : type->tp_name = NULL;
544 : 23648 : PyMem_Free(type->tp_members);
545 : :
546 : 23648 : _PyStaticType_Dealloc(type);
547 : : 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 : 23648 : Py_SET_REFCNT(type, 0);
551 : : #ifdef Py_REF_DEBUG
552 : : _Py_RefTotal--;
553 : : #endif
554 : :
555 : : // Make sure that _PyStructSequence_InitType() will initialize
556 : : // the type again
557 : : assert(Py_REFCNT(type) == 0);
558 : : assert(type->tp_name == NULL);
559 : : }
560 : :
561 : :
562 : : PyTypeObject *
563 : 31888 : _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 : 31888 : n_members = count_members(desc, &n_unnamed_members);
573 [ + - ]: 31888 : members = PyMem_NEW(PyMemberDef, n_members - n_unnamed_members + 1);
574 [ - + ]: 31888 : if (members == NULL) {
575 : : PyErr_NoMemory();
576 : 0 : return NULL;
577 : : }
578 : 31888 : initialize_members(desc, members, n_members);
579 : :
580 : : /* Initialize Slots */
581 : 31888 : slots[0] = (PyType_Slot){Py_tp_dealloc, (destructor)structseq_dealloc};
582 : 31888 : slots[1] = (PyType_Slot){Py_tp_repr, (reprfunc)structseq_repr};
583 : 31888 : slots[2] = (PyType_Slot){Py_tp_doc, (void *)desc->doc};
584 : 31888 : slots[3] = (PyType_Slot){Py_tp_methods, structseq_methods};
585 : 31888 : slots[4] = (PyType_Slot){Py_tp_new, structseq_new};
586 : 31888 : slots[5] = (PyType_Slot){Py_tp_members, members};
587 : 31888 : slots[6] = (PyType_Slot){Py_tp_traverse, (traverseproc)structseq_traverse};
588 : 31888 : 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 : 31888 : spec.name = desc->name;
594 : 31888 : spec.basicsize = sizeof(PyStructSequence) - sizeof(PyObject *);
595 : 31888 : spec.itemsize = sizeof(PyObject *);
596 : 31888 : spec.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags;
597 : 31888 : spec.slots = slots;
598 : :
599 : 31888 : type = (PyTypeObject *)PyType_FromSpecWithBases(&spec, (PyObject *)&PyTuple_Type);
600 : 31888 : PyMem_Free(members);
601 [ - + ]: 31888 : if (type == NULL) {
602 : 0 : return NULL;
603 : : }
604 : :
605 [ - + ]: 31888 : 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 : 31888 : return type;
612 : : }
613 : :
614 : :
615 : : PyTypeObject *
616 : 31884 : PyStructSequence_NewType(PyStructSequence_Desc *desc)
617 : : {
618 : 31884 : return _PyStructSequence_NewType(desc, 0);
619 : : }
|