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 } 298