1#include "Python.h"
2#include "structmember.h" // PyMemberDef
3
4PyDoc_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
21typedef struct {
22 PyListObject list;
23 int state;
24} spamlistobject;
25
26static PyObject *
27spamlist_getstate(spamlistobject *self, PyObject *args)
28{
29 if (!PyArg_ParseTuple(args, ":getstate"))
30 return NULL;
31 return PyLong_FromLong(self->state);
32}
33
34static PyObject *
35spamlist_setstate(spamlistobject *self, PyObject *args)
36{
37 int state;
38
39 if (!PyArg_ParseTuple(args, "i:setstate", &state))
40 return NULL;
41 self->state = state;
42 Py_INCREF(Py_None);
43 return Py_None;
44}
45
46static PyObject *
47spamlist_specialmeth(PyObject *self, PyObject *args, PyObject *kw)
48{
49 PyObject *result = PyTuple_New(3);
50
51 if (result != NULL) {
52 if (self == NULL)
53 self = Py_None;
54 if (kw == NULL)
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
66static 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)(void(*)(void))spamlist_specialmeth,
74 METH_VARARGS | METH_KEYWORDS | METH_CLASS,
75 PyDoc_STR("classmeth(*args, **kw)")},
76 {"staticmeth", (PyCFunction)(void(*)(void))spamlist_specialmeth,
77 METH_VARARGS | METH_KEYWORDS | METH_STATIC,
78 PyDoc_STR("staticmeth(*args, **kw)")},
79 {NULL, NULL},
80};
81
82static int
83spamlist_init(spamlistobject *self, PyObject *args, PyObject *kwds)
84{
85 if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0)
86 return -1;
87 self->state = 0;
88 return 0;
89}
90
91static PyObject *
92spamlist_state_get(spamlistobject *self, void *Py_UNUSED(ignored))
93{
94 return PyLong_FromLong(self->state);
95}
96
97static PyGetSetDef spamlist_getsets[] = {
98 {"state", (getter)spamlist_state_get, NULL,
99 PyDoc_STR("an int variable for demonstration purposes")},
100 {0}
101};
102
103static 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
146typedef struct {
147 PyDictObject dict;
148 int state;
149} spamdictobject;
150
151static PyObject *
152spamdict_getstate(spamdictobject *self, PyObject *args)
153{
154 if (!PyArg_ParseTuple(args, ":getstate"))
155 return NULL;
156 return PyLong_FromLong(self->state);
157}
158
159static PyObject *
160spamdict_setstate(spamdictobject *self, PyObject *args)
161{
162 int state;
163
164 if (!PyArg_ParseTuple(args, "i:setstate", &state))
165 return NULL;
166 self->state = state;
167 Py_INCREF(Py_None);
168 return Py_None;
169}
170
171static 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
179static int
180spamdict_init(spamdictobject *self, PyObject *args, PyObject *kwds)
181{
182 if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
183 return -1;
184 self->state = 0;
185 return 0;
186}
187
188static PyMemberDef spamdict_members[] = {
189 {"state", T_INT, offsetof(spamdictobject, state), READONLY,
190 PyDoc_STR("an int variable for demonstration purposes")},
191 {0}
192};
193
194static 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
235static PyObject *
236spam_bench(PyObject *self, PyObject *args)
237{
238 PyObject *obj, *name, *res;
239 int n = 1000;
240 time_t t0, t1;
241
242 if (!PyArg_ParseTuple(args, "OU|i", &obj, &name, &n))
243 return NULL;
244 t0 = clock();
245 while (--n >= 0) {
246 res = PyObject_GetAttr(obj, name);
247 if (res == NULL)
248 return NULL;
249 Py_DECREF(res);
250 }
251 t1 = clock();
252 return PyFloat_FromDouble((double)(t1-t0) / CLOCKS_PER_SEC);
253}
254
255static PyMethodDef xxsubtype_functions[] = {
256 {"bench", spam_bench, METH_VARARGS},
257 {NULL, NULL} /* sentinel */
258};
259
260static int
261xxsubtype_exec(PyObject* m)
262{
263 /* Fill in deferred data addresses. This must be done before
264 PyType_Ready() is called. Note that PyType_Ready() automatically
265 initializes the ob.ob_type field to &PyType_Type if it's NULL,
266 so it's not necessary to fill in ob_type first. */
267 spamdict_type.tp_base = &PyDict_Type;
268 if (PyType_Ready(&spamdict_type) < 0)
269 return -1;
270
271 spamlist_type.tp_base = &PyList_Type;
272 if (PyType_Ready(&spamlist_type) < 0)
273 return -1;
274
275 if (PyType_Ready(&spamlist_type) < 0)
276 return -1;
277 if (PyType_Ready(&spamdict_type) < 0)
278 return -1;
279
280 Py_INCREF(&spamlist_type);
281 if (PyModule_AddObject(m, "spamlist",
282 (PyObject *) &spamlist_type) < 0)
283 return -1;
284
285 Py_INCREF(&spamdict_type);
286 if (PyModule_AddObject(m, "spamdict",
287 (PyObject *) &spamdict_type) < 0)
288 return -1;
289 return 0;
290}
291
292static struct PyModuleDef_Slot xxsubtype_slots[] = {
293 {Py_mod_exec, xxsubtype_exec},
294 {0, NULL},
295};
296
297static struct PyModuleDef xxsubtypemodule = {
298 PyModuleDef_HEAD_INIT,
299 "xxsubtype",
300 xxsubtype__doc__,
301 0,
302 xxsubtype_functions,
303 xxsubtype_slots,
304 NULL,
305 NULL,
306 NULL
307};
308
309
310PyMODINIT_FUNC
311PyInit_xxsubtype(void)
312{
313 return PyModuleDef_Init(&xxsubtypemodule);
314}
315