ยปCore Development>Code coverage>Objects/structseq.c

Python code coverage for Objects/structseq.c

#countcontent
1n/a/* Implementation helper: a struct that looks like a tuple. See timemodule
2n/a and posixmodule for example uses. */
3n/a
4n/a#include "Python.h"
5n/a#include "structmember.h"
6n/a
7n/astatic const char visible_length_key[] = "n_sequence_fields";
8n/astatic const char real_length_key[] = "n_fields";
9n/astatic const char unnamed_fields_key[] = "n_unnamed_fields";
10n/a
11n/a/* Fields with this name have only a field index, not a field name.
12n/a They are only allowed for indices < n_visible_fields. */
13n/achar *PyStructSequence_UnnamedField = "unnamed field";
14n/a_Py_IDENTIFIER(n_sequence_fields);
15n/a_Py_IDENTIFIER(n_fields);
16n/a_Py_IDENTIFIER(n_unnamed_fields);
17n/a
18n/a#define VISIBLE_SIZE(op) Py_SIZE(op)
19n/a#define VISIBLE_SIZE_TP(tp) PyLong_AsSsize_t( \
20n/a _PyDict_GetItemId((tp)->tp_dict, &PyId_n_sequence_fields))
21n/a
22n/a#define REAL_SIZE_TP(tp) PyLong_AsSsize_t( \
23n/a _PyDict_GetItemId((tp)->tp_dict, &PyId_n_fields))
24n/a#define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op))
25n/a
26n/a#define UNNAMED_FIELDS_TP(tp) PyLong_AsSsize_t( \
27n/a _PyDict_GetItemId((tp)->tp_dict, &PyId_n_unnamed_fields))
28n/a#define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op))
29n/a
30n/a
31n/aPyObject *
32n/aPyStructSequence_New(PyTypeObject *type)
33n/a{
34n/a PyStructSequence *obj;
35n/a Py_ssize_t size = REAL_SIZE_TP(type), i;
36n/a
37n/a obj = PyObject_GC_NewVar(PyStructSequence, type, size);
38n/a if (obj == NULL)
39n/a return NULL;
40n/a /* Hack the size of the variable object, so invisible fields don't appear
41n/a to Python code. */
42n/a Py_SIZE(obj) = VISIBLE_SIZE_TP(type);
43n/a for (i = 0; i < size; i++)
44n/a obj->ob_item[i] = NULL;
45n/a
46n/a return (PyObject*)obj;
47n/a}
48n/a
49n/avoid
50n/aPyStructSequence_SetItem(PyObject* op, Py_ssize_t i, PyObject* v)
51n/a{
52n/a PyStructSequence_SET_ITEM(op, i, v);
53n/a}
54n/a
55n/aPyObject*
56n/aPyStructSequence_GetItem(PyObject* op, Py_ssize_t i)
57n/a{
58n/a return PyStructSequence_GET_ITEM(op, i);
59n/a}
60n/a
61n/astatic void
62n/astructseq_dealloc(PyStructSequence *obj)
63n/a{
64n/a Py_ssize_t i, size;
65n/a
66n/a size = REAL_SIZE(obj);
67n/a for (i = 0; i < size; ++i) {
68n/a Py_XDECREF(obj->ob_item[i]);
69n/a }
70n/a PyObject_GC_Del(obj);
71n/a}
72n/a
73n/astatic PyObject *
74n/astructseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
75n/a{
76n/a PyObject *arg = NULL;
77n/a PyObject *dict = NULL;
78n/a PyObject *ob;
79n/a PyStructSequence *res = NULL;
80n/a Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;
81n/a static char *kwlist[] = {"sequence", "dict", 0};
82n/a
83n/a if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",
84n/a kwlist, &arg, &dict))
85n/a return NULL;
86n/a
87n/a arg = PySequence_Fast(arg, "constructor requires a sequence");
88n/a
89n/a if (!arg) {
90n/a return NULL;
91n/a }
92n/a
93n/a if (dict && !PyDict_Check(dict)) {
94n/a PyErr_Format(PyExc_TypeError,
95n/a "%.500s() takes a dict as second arg, if any",
96n/a type->tp_name);
97n/a Py_DECREF(arg);
98n/a return NULL;
99n/a }
100n/a
101n/a len = PySequence_Fast_GET_SIZE(arg);
102n/a min_len = VISIBLE_SIZE_TP(type);
103n/a max_len = REAL_SIZE_TP(type);
104n/a n_unnamed_fields = UNNAMED_FIELDS_TP(type);
105n/a
106n/a if (min_len != max_len) {
107n/a if (len < min_len) {
108n/a PyErr_Format(PyExc_TypeError,
109n/a "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
110n/a type->tp_name, min_len, len);
111n/a Py_DECREF(arg);
112n/a return NULL;
113n/a }
114n/a
115n/a if (len > max_len) {
116n/a PyErr_Format(PyExc_TypeError,
117n/a "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
118n/a type->tp_name, max_len, len);
119n/a Py_DECREF(arg);
120n/a return NULL;
121n/a }
122n/a }
123n/a else {
124n/a if (len != min_len) {
125n/a PyErr_Format(PyExc_TypeError,
126n/a "%.500s() takes a %zd-sequence (%zd-sequence given)",
127n/a type->tp_name, min_len, len);
128n/a Py_DECREF(arg);
129n/a return NULL;
130n/a }
131n/a }
132n/a
133n/a res = (PyStructSequence*) PyStructSequence_New(type);
134n/a if (res == NULL) {
135n/a Py_DECREF(arg);
136n/a return NULL;
137n/a }
138n/a for (i = 0; i < len; ++i) {
139n/a PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
140n/a Py_INCREF(v);
141n/a res->ob_item[i] = v;
142n/a }
143n/a for (; i < max_len; ++i) {
144n/a if (dict && (ob = PyDict_GetItemString(
145n/a dict, type->tp_members[i-n_unnamed_fields].name))) {
146n/a }
147n/a else {
148n/a ob = Py_None;
149n/a }
150n/a Py_INCREF(ob);
151n/a res->ob_item[i] = ob;
152n/a }
153n/a
154n/a Py_DECREF(arg);
155n/a return (PyObject*) res;
156n/a}
157n/a
158n/a
159n/astatic PyObject *
160n/astructseq_repr(PyStructSequence *obj)
161n/a{
162n/a /* buffer and type size were chosen well considered. */
163n/a#define REPR_BUFFER_SIZE 512
164n/a#define TYPE_MAXSIZE 100
165n/a
166n/a PyTypeObject *typ = Py_TYPE(obj);
167n/a Py_ssize_t i;
168n/a int removelast = 0;
169n/a Py_ssize_t len;
170n/a char buf[REPR_BUFFER_SIZE];
171n/a char *endofbuf, *pbuf = buf;
172n/a
173n/a /* pointer to end of writeable buffer; safes space for "...)\0" */
174n/a endofbuf= &buf[REPR_BUFFER_SIZE-5];
175n/a
176n/a /* "typename(", limited to TYPE_MAXSIZE */
177n/a len = strlen(typ->tp_name) > TYPE_MAXSIZE ? TYPE_MAXSIZE :
178n/a strlen(typ->tp_name);
179n/a strncpy(pbuf, typ->tp_name, len);
180n/a pbuf += len;
181n/a *pbuf++ = '(';
182n/a
183n/a for (i=0; i < VISIBLE_SIZE(obj); i++) {
184n/a PyObject *val, *repr;
185n/a const char *cname, *crepr;
186n/a
187n/a cname = typ->tp_members[i].name;
188n/a if (cname == NULL) {
189n/a PyErr_Format(PyExc_SystemError, "In structseq_repr(), member %d name is NULL"
190n/a " for type %.500s", i, typ->tp_name);
191n/a return NULL;
192n/a }
193n/a val = PyStructSequence_GET_ITEM(obj, i);
194n/a repr = PyObject_Repr(val);
195n/a if (repr == NULL)
196n/a return NULL;
197n/a crepr = PyUnicode_AsUTF8(repr);
198n/a if (crepr == NULL) {
199n/a Py_DECREF(repr);
200n/a return NULL;
201n/a }
202n/a
203n/a /* + 3: keep space for "=" and ", " */
204n/a len = strlen(cname) + strlen(crepr) + 3;
205n/a if ((pbuf+len) <= endofbuf) {
206n/a strcpy(pbuf, cname);
207n/a pbuf += strlen(cname);
208n/a *pbuf++ = '=';
209n/a strcpy(pbuf, crepr);
210n/a pbuf += strlen(crepr);
211n/a *pbuf++ = ',';
212n/a *pbuf++ = ' ';
213n/a removelast = 1;
214n/a Py_DECREF(repr);
215n/a }
216n/a else {
217n/a strcpy(pbuf, "...");
218n/a pbuf += 3;
219n/a removelast = 0;
220n/a Py_DECREF(repr);
221n/a break;
222n/a }
223n/a }
224n/a if (removelast) {
225n/a /* overwrite last ", " */
226n/a pbuf-=2;
227n/a }
228n/a *pbuf++ = ')';
229n/a *pbuf = '\0';
230n/a
231n/a return PyUnicode_FromString(buf);
232n/a}
233n/a
234n/astatic PyObject *
235n/astructseq_reduce(PyStructSequence* self)
236n/a{
237n/a PyObject* tup = NULL;
238n/a PyObject* dict = NULL;
239n/a PyObject* result;
240n/a Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields, i;
241n/a
242n/a n_fields = REAL_SIZE(self);
243n/a n_visible_fields = VISIBLE_SIZE(self);
244n/a n_unnamed_fields = UNNAMED_FIELDS(self);
245n/a tup = PyTuple_New(n_visible_fields);
246n/a if (!tup)
247n/a goto error;
248n/a
249n/a dict = PyDict_New();
250n/a if (!dict)
251n/a goto error;
252n/a
253n/a for (i = 0; i < n_visible_fields; i++) {
254n/a Py_INCREF(self->ob_item[i]);
255n/a PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
256n/a }
257n/a
258n/a for (; i < n_fields; i++) {
259n/a const char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;
260n/a if (PyDict_SetItemString(dict, n, self->ob_item[i]) < 0)
261n/a goto error;
262n/a }
263n/a
264n/a result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);
265n/a
266n/a Py_DECREF(tup);
267n/a Py_DECREF(dict);
268n/a
269n/a return result;
270n/a
271n/aerror:
272n/a Py_XDECREF(tup);
273n/a Py_XDECREF(dict);
274n/a return NULL;
275n/a}
276n/a
277n/astatic PyMethodDef structseq_methods[] = {
278n/a {"__reduce__", (PyCFunction)structseq_reduce, METH_NOARGS, NULL},
279n/a {NULL, NULL}
280n/a};
281n/a
282n/astatic PyTypeObject _struct_sequence_template = {
283n/a PyVarObject_HEAD_INIT(&PyType_Type, 0)
284n/a NULL, /* tp_name */
285n/a sizeof(PyStructSequence) - sizeof(PyObject *), /* tp_basicsize */
286n/a sizeof(PyObject *), /* tp_itemsize */
287n/a (destructor)structseq_dealloc, /* tp_dealloc */
288n/a 0, /* tp_print */
289n/a 0, /* tp_getattr */
290n/a 0, /* tp_setattr */
291n/a 0, /* tp_reserved */
292n/a (reprfunc)structseq_repr, /* tp_repr */
293n/a 0, /* tp_as_number */
294n/a 0, /* tp_as_sequence */
295n/a 0, /* tp_as_mapping */
296n/a 0, /* tp_hash */
297n/a 0, /* tp_call */
298n/a 0, /* tp_str */
299n/a 0, /* tp_getattro */
300n/a 0, /* tp_setattro */
301n/a 0, /* tp_as_buffer */
302n/a Py_TPFLAGS_DEFAULT, /* tp_flags */
303n/a NULL, /* tp_doc */
304n/a 0, /* tp_traverse */
305n/a 0, /* tp_clear */
306n/a 0, /* tp_richcompare */
307n/a 0, /* tp_weaklistoffset */
308n/a 0, /* tp_iter */
309n/a 0, /* tp_iternext */
310n/a structseq_methods, /* tp_methods */
311n/a NULL, /* tp_members */
312n/a 0, /* tp_getset */
313n/a 0, /* tp_base */
314n/a 0, /* tp_dict */
315n/a 0, /* tp_descr_get */
316n/a 0, /* tp_descr_set */
317n/a 0, /* tp_dictoffset */
318n/a 0, /* tp_init */
319n/a 0, /* tp_alloc */
320n/a structseq_new, /* tp_new */
321n/a};
322n/a
323n/aint
324n/aPyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
325n/a{
326n/a PyObject *dict;
327n/a PyMemberDef* members;
328n/a Py_ssize_t n_members, n_unnamed_members, i, k;
329n/a PyObject *v;
330n/a
331n/a#ifdef Py_TRACE_REFS
332n/a /* if the type object was chained, unchain it first
333n/a before overwriting its storage */
334n/a if (type->ob_base.ob_base._ob_next) {
335n/a _Py_ForgetReference((PyObject*)type);
336n/a }
337n/a#endif
338n/a
339n/a n_unnamed_members = 0;
340n/a for (i = 0; desc->fields[i].name != NULL; ++i)
341n/a if (desc->fields[i].name == PyStructSequence_UnnamedField)
342n/a n_unnamed_members++;
343n/a n_members = i;
344n/a
345n/a memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
346n/a type->tp_base = &PyTuple_Type;
347n/a type->tp_name = desc->name;
348n/a type->tp_doc = desc->doc;
349n/a
350n/a members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
351n/a if (members == NULL) {
352n/a PyErr_NoMemory();
353n/a return -1;
354n/a }
355n/a
356n/a for (i = k = 0; i < n_members; ++i) {
357n/a if (desc->fields[i].name == PyStructSequence_UnnamedField)
358n/a continue;
359n/a members[k].name = desc->fields[i].name;
360n/a members[k].type = T_OBJECT;
361n/a members[k].offset = offsetof(PyStructSequence, ob_item)
362n/a + i * sizeof(PyObject*);
363n/a members[k].flags = READONLY;
364n/a members[k].doc = desc->fields[i].doc;
365n/a k++;
366n/a }
367n/a members[k].name = NULL;
368n/a
369n/a type->tp_members = members;
370n/a
371n/a if (PyType_Ready(type) < 0)
372n/a return -1;
373n/a Py_INCREF(type);
374n/a
375n/a dict = type->tp_dict;
376n/a#define SET_DICT_FROM_SIZE(key, value) \
377n/a do { \
378n/a v = PyLong_FromSsize_t(value); \
379n/a if (v == NULL) \
380n/a return -1; \
381n/a if (PyDict_SetItemString(dict, key, v) < 0) { \
382n/a Py_DECREF(v); \
383n/a return -1; \
384n/a } \
385n/a Py_DECREF(v); \
386n/a } while (0)
387n/a
388n/a SET_DICT_FROM_SIZE(visible_length_key, desc->n_in_sequence);
389n/a SET_DICT_FROM_SIZE(real_length_key, n_members);
390n/a SET_DICT_FROM_SIZE(unnamed_fields_key, n_unnamed_members);
391n/a
392n/a return 0;
393n/a}
394n/a
395n/avoid
396n/aPyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
397n/a{
398n/a (void)PyStructSequence_InitType2(type, desc);
399n/a}
400n/a
401n/aPyTypeObject*
402n/aPyStructSequence_NewType(PyStructSequence_Desc *desc)
403n/a{
404n/a PyTypeObject *result;
405n/a
406n/a result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0);
407n/a if (result == NULL)
408n/a return NULL;
409n/a if (PyStructSequence_InitType2(result, desc) < 0) {
410n/a Py_DECREF(result);
411n/a return NULL;
412n/a }
413n/a return result;
414n/a}
415n/a
416n/aint _PyStructSequence_Init(void)
417n/a{
418n/a if (_PyUnicode_FromId(&PyId_n_sequence_fields) == NULL
419n/a || _PyUnicode_FromId(&PyId_n_fields) == NULL
420n/a || _PyUnicode_FromId(&PyId_n_unnamed_fields) == NULL)
421n/a return -1;
422n/a
423n/a return 0;
424n/a}