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"))
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))
40 return NULL;
41 self->state = state;
42 return Py_NewRef(Py_None);
43 }
44
45 static PyObject *
46 spamlist_specialmeth(PyObject *self, PyObject *args, PyObject *kw)
47 {
48 PyObject *result = PyTuple_New(3);
49
50 if (result != NULL) {
51 if (self == NULL)
52 self = Py_None;
53 if (kw == NULL)
54 kw = Py_None;
55 PyTuple_SET_ITEM(result, 0, Py_NewRef(self));
56 PyTuple_SET_ITEM(result, 1, Py_NewRef(args));
57 PyTuple_SET_ITEM(result, 2, Py_NewRef(kw));
58 }
59 return result;
60 }
61
62 static PyMethodDef spamlist_methods[] = {
63 {"getstate", (PyCFunction)spamlist_getstate, METH_VARARGS,
64 PyDoc_STR("getstate() -> state")},
65 {"setstate", (PyCFunction)spamlist_setstate, METH_VARARGS,
66 PyDoc_STR("setstate(state)")},
67 /* These entries differ only in the flags; they are used by the tests
68 in test.test_descr. */
69 {"classmeth", _PyCFunction_CAST(spamlist_specialmeth),
70 METH_VARARGS | METH_KEYWORDS | METH_CLASS,
71 PyDoc_STR("classmeth(*args, **kw)")},
72 {"staticmeth", _PyCFunction_CAST(spamlist_specialmeth),
73 METH_VARARGS | METH_KEYWORDS | METH_STATIC,
74 PyDoc_STR("staticmeth(*args, **kw)")},
75 {NULL, NULL},
76 };
77
78 static int
79 spamlist_init(spamlistobject *self, PyObject *args, PyObject *kwds)
80 {
81 if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0)
82 return -1;
83 self->state = 0;
84 return 0;
85 }
86
87 static PyObject *
88 spamlist_state_get(spamlistobject *self, void *Py_UNUSED(ignored))
89 {
90 return PyLong_FromLong(self->state);
91 }
92
93 static PyGetSetDef spamlist_getsets[] = {
94 {"state", (getter)spamlist_state_get, NULL,
95 PyDoc_STR("an int variable for demonstration purposes")},
96 {0}
97 };
98
99 static PyTypeObject spamlist_type = {
100 PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
101 "xxsubtype.spamlist",
102 sizeof(spamlistobject),
103 0,
104 0, /* tp_dealloc */
105 0, /* tp_vectorcall_offset */
106 0, /* tp_getattr */
107 0, /* tp_setattr */
108 0, /* tp_as_async */
109 0, /* tp_repr */
110 0, /* tp_as_number */
111 0, /* tp_as_sequence */
112 0, /* tp_as_mapping */
113 0, /* tp_hash */
114 0, /* tp_call */
115 0, /* tp_str */
116 0, /* tp_getattro */
117 0, /* tp_setattro */
118 0, /* tp_as_buffer */
119 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
120 0, /* tp_doc */
121 0, /* tp_traverse */
122 0, /* tp_clear */
123 0, /* tp_richcompare */
124 0, /* tp_weaklistoffset */
125 0, /* tp_iter */
126 0, /* tp_iternext */
127 spamlist_methods, /* tp_methods */
128 0, /* tp_members */
129 spamlist_getsets, /* tp_getset */
130 DEFERRED_ADDRESS(&PyList_Type), /* tp_base */
131 0, /* tp_dict */
132 0, /* tp_descr_get */
133 0, /* tp_descr_set */
134 0, /* tp_dictoffset */
135 (initproc)spamlist_init, /* tp_init */
136 0, /* tp_alloc */
137 0, /* tp_new */
138 };
139
140 /* spamdict -- a dict subtype */
141
142 typedef struct {
143 PyDictObject dict;
144 int state;
145 } spamdictobject;
146
147 static PyObject *
148 spamdict_getstate(spamdictobject *self, PyObject *args)
149 {
150 if (!PyArg_ParseTuple(args, ":getstate"))
151 return NULL;
152 return PyLong_FromLong(self->state);
153 }
154
155 static PyObject *
156 spamdict_setstate(spamdictobject *self, PyObject *args)
157 {
158 int state;
159
160 if (!PyArg_ParseTuple(args, "i:setstate", &state))
161 return NULL;
162 self->state = state;
163 return Py_NewRef(Py_None);
164 }
165
166 static PyMethodDef spamdict_methods[] = {
167 {"getstate", (PyCFunction)spamdict_getstate, METH_VARARGS,
168 PyDoc_STR("getstate() -> state")},
169 {"setstate", (PyCFunction)spamdict_setstate, METH_VARARGS,
170 PyDoc_STR("setstate(state)")},
171 {NULL, NULL},
172 };
173
174 static int
175 spamdict_init(spamdictobject *self, PyObject *args, PyObject *kwds)
176 {
177 if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
178 return -1;
179 self->state = 0;
180 return 0;
181 }
182
183 static PyMemberDef spamdict_members[] = {
184 {"state", T_INT, offsetof(spamdictobject, state), READONLY,
185 PyDoc_STR("an int variable for demonstration purposes")},
186 {0}
187 };
188
189 static PyTypeObject spamdict_type = {
190 PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
191 "xxsubtype.spamdict",
192 sizeof(spamdictobject),
193 0,
194 0, /* tp_dealloc */
195 0, /* tp_vectorcall_offset */
196 0, /* tp_getattr */
197 0, /* tp_setattr */
198 0, /* tp_as_async */
199 0, /* tp_repr */
200 0, /* tp_as_number */
201 0, /* tp_as_sequence */
202 0, /* tp_as_mapping */
203 0, /* tp_hash */
204 0, /* tp_call */
205 0, /* tp_str */
206 0, /* tp_getattro */
207 0, /* tp_setattro */
208 0, /* tp_as_buffer */
209 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
210 0, /* tp_doc */
211 0, /* tp_traverse */
212 0, /* tp_clear */
213 0, /* tp_richcompare */
214 0, /* tp_weaklistoffset */
215 0, /* tp_iter */
216 0, /* tp_iternext */
217 spamdict_methods, /* tp_methods */
218 spamdict_members, /* tp_members */
219 0, /* tp_getset */
220 DEFERRED_ADDRESS(&PyDict_Type), /* tp_base */
221 0, /* tp_dict */
222 0, /* tp_descr_get */
223 0, /* tp_descr_set */
224 0, /* tp_dictoffset */
225 (initproc)spamdict_init, /* tp_init */
226 0, /* tp_alloc */
227 0, /* tp_new */
228 };
229
230 static PyObject *
231 spam_bench(PyObject *self, PyObject *args)
232 {
233 PyObject *obj, *name, *res;
234 int n = 1000;
235 time_t t0 = 0, t1 = 0;
236
237 if (!PyArg_ParseTuple(args, "OU|i", &obj, &name, &n))
238 return NULL;
239 #ifdef HAVE_CLOCK
240 t0 = clock();
241 while (--n >= 0) {
242 res = PyObject_GetAttr(obj, name);
243 if (res == NULL)
244 return NULL;
245 Py_DECREF(res);
246 }
247 t1 = clock();
248 #endif
249 return PyFloat_FromDouble((double)(t1-t0) / CLOCKS_PER_SEC);
250 }
251
252 static PyMethodDef xxsubtype_functions[] = {
253 {"bench", spam_bench, METH_VARARGS},
254 {NULL, NULL} /* sentinel */
255 };
256
257 static int
258 xxsubtype_exec(PyObject* m)
259 {
260 /* Fill in deferred data addresses. This must be done before
261 PyType_Ready() is called. Note that PyType_Ready() automatically
262 initializes the ob.ob_type field to &PyType_Type if it's NULL,
263 so it's not necessary to fill in ob_type first. */
264 spamdict_type.tp_base = &PyDict_Type;
265 if (PyType_Ready(&spamdict_type) < 0)
266 return -1;
267
268 spamlist_type.tp_base = &PyList_Type;
269 if (PyType_Ready(&spamlist_type) < 0)
270 return -1;
271
272 if (PyType_Ready(&spamlist_type) < 0)
273 return -1;
274 if (PyType_Ready(&spamdict_type) < 0)
275 return -1;
276
277 if (PyModule_AddObjectRef(m, "spamlist", (PyObject *)&spamlist_type) < 0)
278 return -1;
279
280 if (PyModule_AddObjectRef(m, "spamdict", (PyObject *)&spamdict_type) < 0)
281 return -1;
282 return 0;
283 }
284
285 static struct PyModuleDef_Slot xxsubtype_slots[] = {
286 {Py_mod_exec, xxsubtype_exec},
287 {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
288 {0, NULL},
289 };
290
291 static struct PyModuleDef xxsubtypemodule = {
292 PyModuleDef_HEAD_INIT,
293 "xxsubtype",
294 xxsubtype__doc__,
295 0,
296 xxsubtype_functions,
297 xxsubtype_slots,
298 NULL,
299 NULL,
300 NULL
301 };
302
303
304 PyMODINIT_FUNC
305 PyInit_xxsubtype(void)
306 {
307 return PyModuleDef_Init(&xxsubtypemodule);
308 }