|
1 #include "Python.h" |
|
2 #include "structmember.h" |
|
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 PyInt_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 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) { |
|
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 |
|
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)spamlist_specialmeth, |
|
74 METH_VARARGS | METH_KEYWORDS | METH_CLASS, |
|
75 PyDoc_STR("classmeth(*args, **kw)")}, |
|
76 {"staticmeth", (PyCFunction)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) |
|
86 return -1; |
|
87 self->state = 0; |
|
88 return 0; |
|
89 } |
|
90 |
|
91 static PyObject * |
|
92 spamlist_state_get(spamlistobject *self) |
|
93 { |
|
94 return PyInt_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_print */ |
|
110 0, /* tp_getattr */ |
|
111 0, /* tp_setattr */ |
|
112 0, /* tp_compare */ |
|
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")) |
|
155 return NULL; |
|
156 return PyInt_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)) |
|
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) |
|
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_print */ |
|
201 0, /* tp_getattr */ |
|
202 0, /* tp_setattr */ |
|
203 0, /* tp_compare */ |
|
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, t1; |
|
241 |
|
242 if (!PyArg_ParseTuple(args, "OS|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 |
|
255 static PyMethodDef xxsubtype_functions[] = { |
|
256 {"bench", spam_bench, METH_VARARGS}, |
|
257 {NULL, NULL} /* sentinel */ |
|
258 }; |
|
259 |
|
260 PyMODINIT_FUNC |
|
261 initxxsubtype(void) |
|
262 { |
|
263 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) |
|
271 return; |
|
272 |
|
273 spamlist_type.tp_base = &PyList_Type; |
|
274 if (PyType_Ready(&spamlist_type) < 0) |
|
275 return; |
|
276 |
|
277 m = Py_InitModule3("xxsubtype", |
|
278 xxsubtype_functions, |
|
279 xxsubtype__doc__); |
|
280 if (m == NULL) |
|
281 return; |
|
282 |
|
283 if (PyType_Ready(&spamlist_type) < 0) |
|
284 return; |
|
285 if (PyType_Ready(&spamdict_type) < 0) |
|
286 return; |
|
287 |
|
288 Py_INCREF(&spamlist_type); |
|
289 if (PyModule_AddObject(m, "spamlist", |
|
290 (PyObject *) &spamlist_type) < 0) |
|
291 return; |
|
292 |
|
293 Py_INCREF(&spamdict_type); |
|
294 if (PyModule_AddObject(m, "spamdict", |
|
295 (PyObject *) &spamdict_type) < 0) |
|
296 return; |
|
297 } |