Coverage Report

Created: 2022-07-08 09:39

/home/mdboom/Work/builds/cpython/Modules/xxsubtype.c
Line
Count
Source (jump to first uncovered line)
1
#include "Python.h"
2
#include "structmember.h"         // PyMemberDef
3
4
PyDoc_STRVAR(xxsubtype__doc__,
5
"xxsubtype is an example module showing how to subtype builtin types from C.\n"
6
"test_descr.py in the standard test suite requires it in order to complete.\n"
7
"If you don't care about the examples, and don't intend to run the Python\n"
8
"test suite, you can recompile Python without Modules/xxsubtype.c.");
9
10
/* We link this module statically for convenience.  If compiled as a shared
11
   library instead, some compilers don't allow addresses of Python objects
12
   defined in other libraries to be used in static initializers here.  The
13
   DEFERRED_ADDRESS macro is used to tag the slots where such addresses
14
   appear; the module init function must fill in the tagged slots at runtime.
15
   The argument is for documentation -- the macro ignores it.
16
*/
17
#define DEFERRED_ADDRESS(ADDR) 0
18
19
/* spamlist -- a list subtype */
20
21
typedef struct {
22
    PyListObject list;
23
    int state;
24
} spamlistobject;
25
26
static PyObject *
27
spamlist_getstate(spamlistobject *self, PyObject *args)
28
{
29
    if (!PyArg_ParseTuple(args, ":getstate"))
  Branch (29:9): [True: 0, False: 2]
30
        return NULL;
31
    return PyLong_FromLong(self->state);
32
}
33
34
static PyObject *
35
spamlist_setstate(spamlistobject *self, PyObject *args)
36
{
37
    int state;
38
39
    if (!PyArg_ParseTuple(args, "i:setstate", &state))
  Branch (39:9): [True: 0, False: 1]
40
        return NULL;
41
    self->state = state;
42
    Py_INCREF(Py_None);
43
    return Py_None;
44
}
45
46
static PyObject *
47
spamlist_specialmeth(PyObject *self, PyObject *args, PyObject *kw)
48
{
49
    PyObject *result = PyTuple_New(3);
50
51
    if (result != NULL) {
  Branch (51:9): [True: 6, False: 0]
52
        if (self == NULL)
  Branch (52:13): [True: 2, False: 4]
53
            self = Py_None;
54
        if (kw == NULL)
  Branch (54:13): [True: 0, False: 6]
55
            kw = Py_None;
56
        Py_INCREF(self);
57
        PyTuple_SET_ITEM(result, 0, self);
58
        Py_INCREF(args);
59
        PyTuple_SET_ITEM(result, 1, args);
60
        Py_INCREF(kw);
61
        PyTuple_SET_ITEM(result, 2, kw);
62
    }
63
    return result;
64
}
65
66
static PyMethodDef spamlist_methods[] = {
67
    {"getstate", (PyCFunction)spamlist_getstate, METH_VARARGS,
68
        PyDoc_STR("getstate() -> state")},
69
    {"setstate", (PyCFunction)spamlist_setstate, METH_VARARGS,
70
        PyDoc_STR("setstate(state)")},
71
    /* These entries differ only in the flags; they are used by the tests
72
       in test.test_descr. */
73
    {"classmeth", _PyCFunction_CAST(spamlist_specialmeth),
74
        METH_VARARGS | METH_KEYWORDS | METH_CLASS,
75
        PyDoc_STR("classmeth(*args, **kw)")},
76
    {"staticmeth", _PyCFunction_CAST(spamlist_specialmeth),
77
        METH_VARARGS | METH_KEYWORDS | METH_STATIC,
78
        PyDoc_STR("staticmeth(*args, **kw)")},
79
    {NULL,      NULL},
80
};
81
82
static int
83
spamlist_init(spamlistobject *self, PyObject *args, PyObject *kwds)
84
{
85
    if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0)
  Branch (85:9): [True: 0, False: 39]
86
        return -1;
87
    self->state = 0;
88
    return 0;
89
}
90
91
static PyObject *
92
spamlist_state_get(spamlistobject *self, void *Py_UNUSED(ignored))
93
{
94
    return PyLong_FromLong(self->state);
95
}
96
97
static PyGetSetDef spamlist_getsets[] = {
98
    {"state", (getter)spamlist_state_get, NULL,
99
     PyDoc_STR("an int variable for demonstration purposes")},
100
    {0}
101
};
102
103
static PyTypeObject spamlist_type = {
104
    PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
105
    "xxsubtype.spamlist",
106
    sizeof(spamlistobject),
107
    0,
108
    0,                                          /* tp_dealloc */
109
    0,                                          /* tp_vectorcall_offset */
110
    0,                                          /* tp_getattr */
111
    0,                                          /* tp_setattr */
112
    0,                                          /* tp_as_async */
113
    0,                                          /* tp_repr */
114
    0,                                          /* tp_as_number */
115
    0,                                          /* tp_as_sequence */
116
    0,                                          /* tp_as_mapping */
117
    0,                                          /* tp_hash */
118
    0,                                          /* tp_call */
119
    0,                                          /* tp_str */
120
    0,                                          /* tp_getattro */
121
    0,                                          /* tp_setattro */
122
    0,                                          /* tp_as_buffer */
123
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
124
    0,                                          /* tp_doc */
125
    0,                                          /* tp_traverse */
126
    0,                                          /* tp_clear */
127
    0,                                          /* tp_richcompare */
128
    0,                                          /* tp_weaklistoffset */
129
    0,                                          /* tp_iter */
130
    0,                                          /* tp_iternext */
131
    spamlist_methods,                           /* tp_methods */
132
    0,                                          /* tp_members */
133
    spamlist_getsets,                           /* tp_getset */
134
    DEFERRED_ADDRESS(&PyList_Type),             /* tp_base */
135
    0,                                          /* tp_dict */
136
    0,                                          /* tp_descr_get */
137
    0,                                          /* tp_descr_set */
138
    0,                                          /* tp_dictoffset */
139
    (initproc)spamlist_init,                    /* tp_init */
140
    0,                                          /* tp_alloc */
141
    0,                                          /* tp_new */
142
};
143
144
/* spamdict -- a dict subtype */
145
146
typedef struct {
147
    PyDictObject dict;
148
    int state;
149
} spamdictobject;
150
151
static PyObject *
152
spamdict_getstate(spamdictobject *self, PyObject *args)
153
{
154
    if (!PyArg_ParseTuple(args, ":getstate"))
  Branch (154:9): [True: 0, False: 2]
155
        return NULL;
156
    return PyLong_FromLong(self->state);
157
}
158
159
static PyObject *
160
spamdict_setstate(spamdictobject *self, PyObject *args)
161
{
162
    int state;
163
164
    if (!PyArg_ParseTuple(args, "i:setstate", &state))
  Branch (164:9): [True: 0, False: 1]
165
        return NULL;
166
    self->state = state;
167
    Py_INCREF(Py_None);
168
    return Py_None;
169
}
170
171
static PyMethodDef spamdict_methods[] = {
172
    {"getstate", (PyCFunction)spamdict_getstate, METH_VARARGS,
173
        PyDoc_STR("getstate() -> state")},
174
    {"setstate", (PyCFunction)spamdict_setstate, METH_VARARGS,
175
        PyDoc_STR("setstate(state)")},
176
    {NULL,      NULL},
177
};
178
179
static int
180
spamdict_init(spamdictobject *self, PyObject *args, PyObject *kwds)
181
{
182
    if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
  Branch (182:9): [True: 0, False: 12]
183
        return -1;
184
    self->state = 0;
185
    return 0;
186
}
187
188
static PyMemberDef spamdict_members[] = {
189
    {"state", T_INT, offsetof(spamdictobject, state), READONLY,
190
     PyDoc_STR("an int variable for demonstration purposes")},
191
    {0}
192
};
193
194
static PyTypeObject spamdict_type = {
195
    PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
196
    "xxsubtype.spamdict",
197
    sizeof(spamdictobject),
198
    0,
199
    0,                                          /* tp_dealloc */
200
    0,                                          /* tp_vectorcall_offset */
201
    0,                                          /* tp_getattr */
202
    0,                                          /* tp_setattr */
203
    0,                                          /* tp_as_async */
204
    0,                                          /* tp_repr */
205
    0,                                          /* tp_as_number */
206
    0,                                          /* tp_as_sequence */
207
    0,                                          /* tp_as_mapping */
208
    0,                                          /* tp_hash */
209
    0,                                          /* tp_call */
210
    0,                                          /* tp_str */
211
    0,                                          /* tp_getattro */
212
    0,                                          /* tp_setattro */
213
    0,                                          /* tp_as_buffer */
214
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
215
    0,                                          /* tp_doc */
216
    0,                                          /* tp_traverse */
217
    0,                                          /* tp_clear */
218
    0,                                          /* tp_richcompare */
219
    0,                                          /* tp_weaklistoffset */
220
    0,                                          /* tp_iter */
221
    0,                                          /* tp_iternext */
222
    spamdict_methods,                           /* tp_methods */
223
    spamdict_members,                           /* tp_members */
224
    0,                                          /* tp_getset */
225
    DEFERRED_ADDRESS(&PyDict_Type),             /* tp_base */
226
    0,                                          /* tp_dict */
227
    0,                                          /* tp_descr_get */
228
    0,                                          /* tp_descr_set */
229
    0,                                          /* tp_dictoffset */
230
    (initproc)spamdict_init,                    /* tp_init */
231
    0,                                          /* tp_alloc */
232
    0,                                          /* tp_new */
233
};
234
235
static PyObject *
236
spam_bench(PyObject *self, PyObject *args)
237
{
238
    PyObject *obj, *name, *res;
239
    int n = 1000;
240
    time_t t0 = 0, t1 = 0;
241
242
    if (!PyArg_ParseTuple(args, "OU|i", &obj, &name, &n))
  Branch (242:9): [True: 0, False: 0]
243
        return NULL;
244
#ifdef HAVE_CLOCK
245
    t0 = clock();
246
    while (--n >= 0) {
  Branch (246:12): [True: 0, False: 0]
247
        res = PyObject_GetAttr(obj, name);
248
        if (res == NULL)
  Branch (248:13): [True: 0, False: 0]
249
            return NULL;
250
        Py_DECREF(res);
251
    }
252
    t1 = clock();
253
#endif
254
    return PyFloat_FromDouble((double)(t1-t0) / CLOCKS_PER_SEC);
255
}
256
257
static PyMethodDef xxsubtype_functions[] = {
258
    {"bench",           spam_bench,     METH_VARARGS},
259
    {NULL,              NULL}           /* sentinel */
260
};
261
262
static int
263
xxsubtype_exec(PyObject* m)
264
{
265
    /* Fill in deferred data addresses.  This must be done before
266
       PyType_Ready() is called.  Note that PyType_Ready() automatically
267
       initializes the ob.ob_type field to &PyType_Type if it's NULL,
268
       so it's not necessary to fill in ob_type first. */
269
    spamdict_type.tp_base = &PyDict_Type;
270
    if (PyType_Ready(&spamdict_type) < 0)
  Branch (270:9): [True: 0, False: 1]
271
        return -1;
272
273
    spamlist_type.tp_base = &PyList_Type;
274
    if (PyType_Ready(&spamlist_type) < 0)
  Branch (274:9): [True: 0, False: 1]
275
        return -1;
276
277
    if (PyType_Ready(&spamlist_type) < 0)
  Branch (277:9): [True: 0, False: 1]
278
        return -1;
279
    if (PyType_Ready(&spamdict_type) < 0)
  Branch (279:9): [True: 0, False: 1]
280
        return -1;
281
282
    Py_INCREF(&spamlist_type);
283
    if (PyModule_AddObject(m, "spamlist",
  Branch (283:9): [True: 0, False: 1]
284
                           (PyObject *) &spamlist_type) < 0)
285
        return -1;
286
287
    Py_INCREF(&spamdict_type);
288
    if (PyModule_AddObject(m, "spamdict",
  Branch (288:9): [True: 0, False: 1]
289
                           (PyObject *) &spamdict_type) < 0)
290
        return -1;
291
    return 0;
292
}
293
294
static struct PyModuleDef_Slot xxsubtype_slots[] = {
295
    {Py_mod_exec, xxsubtype_exec},
296
    {0, NULL},
297
};
298
299
static struct PyModuleDef xxsubtypemodule = {
300
    PyModuleDef_HEAD_INIT,
301
    "xxsubtype",
302
    xxsubtype__doc__,
303
    0,
304
    xxsubtype_functions,
305
    xxsubtype_slots,
306
    NULL,
307
    NULL,
308
    NULL
309
};
310
311
312
PyMODINIT_FUNC
313
PyInit_xxsubtype(void)
314
{
315
    return PyModuleDef_Init(&xxsubtypemodule);
316
}