1#include "Python.h" 2#include "structmember.h" 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 PyInt_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)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 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) 93{ 94 return PyInt_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_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 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 PyInt_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_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 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, "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 255static PyMethodDef xxsubtype_functions[] = { 256 {"bench", spam_bench, METH_VARARGS}, 257 {NULL, NULL} /* sentinel */ 258}; 259 260PyMODINIT_FUNC 261initxxsubtype(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