| #include "Python.h" |
| #include "structmember.h" |
| |
| PyDoc_STRVAR(xxsubtype__doc__, |
| "xxsubtype is an example module showing how to subtype builtin types from C.\n" |
| "test_descr.py in the standard test suite requires it in order to complete.\n" |
| "If you don't care about the examples, and don't intend to run the Python\n" |
| "test suite, you can recompile Python without Modules/xxsubtype.c."); |
| |
| /* We link this module statically for convenience. If compiled as a shared |
| library instead, some compilers don't allow addresses of Python objects |
| defined in other libraries to be used in static initializers here. The |
| DEFERRED_ADDRESS macro is used to tag the slots where such addresses |
| appear; the module init function must fill in the tagged slots at runtime. |
| The argument is for documentation -- the macro ignores it. |
| */ |
| #define DEFERRED_ADDRESS(ADDR) 0 |
| |
| /* spamlist -- a list subtype */ |
| |
| typedef struct { |
| PyListObject list; |
| int state; |
| } spamlistobject; |
| |
| static PyObject * |
| spamlist_getstate(spamlistobject *self, PyObject *args) |
| { |
| if (!PyArg_ParseTuple(args, ":getstate")) |
| return NULL; |
| return PyLong_FromLong(self->state); |
| } |
| |
| static PyObject * |
| spamlist_setstate(spamlistobject *self, PyObject *args) |
| { |
| int state; |
| |
| if (!PyArg_ParseTuple(args, "i:setstate", &state)) |
| return NULL; |
| self->state = state; |
| Py_INCREF(Py_None); |
| return Py_None; |
| } |
| |
| static PyObject * |
| spamlist_specialmeth(PyObject *self, PyObject *args, PyObject *kw) |
| { |
| PyObject *result = PyTuple_New(3); |
| |
| if (result != NULL) { |
| if (self == NULL) |
| self = Py_None; |
| if (kw == NULL) |
| kw = Py_None; |
| Py_INCREF(self); |
| PyTuple_SET_ITEM(result, 0, self); |
| Py_INCREF(args); |
| PyTuple_SET_ITEM(result, 1, args); |
| Py_INCREF(kw); |
| PyTuple_SET_ITEM(result, 2, kw); |
| } |
| return result; |
| } |
| |
| static PyMethodDef spamlist_methods[] = { |
| {"getstate", (PyCFunction)spamlist_getstate, METH_VARARGS, |
| PyDoc_STR("getstate() -> state")}, |
| {"setstate", (PyCFunction)spamlist_setstate, METH_VARARGS, |
| PyDoc_STR("setstate(state)")}, |
| /* These entries differ only in the flags; they are used by the tests |
| in test.test_descr. */ |
| {"classmeth", (PyCFunction)spamlist_specialmeth, |
| METH_VARARGS | METH_KEYWORDS | METH_CLASS, |
| PyDoc_STR("classmeth(*args, **kw)")}, |
| {"staticmeth", (PyCFunction)spamlist_specialmeth, |
| METH_VARARGS | METH_KEYWORDS | METH_STATIC, |
| PyDoc_STR("staticmeth(*args, **kw)")}, |
| {NULL, NULL}, |
| }; |
| |
| static int |
| spamlist_init(spamlistobject *self, PyObject *args, PyObject *kwds) |
| { |
| if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0) |
| return -1; |
| self->state = 0; |
| return 0; |
| } |
| |
| static PyObject * |
| spamlist_state_get(spamlistobject *self) |
| { |
| return PyLong_FromLong(self->state); |
| } |
| |
| static PyGetSetDef spamlist_getsets[] = { |
| {"state", (getter)spamlist_state_get, NULL, |
| PyDoc_STR("an int variable for demonstration purposes")}, |
| {0} |
| }; |
| |
| static PyTypeObject spamlist_type = { |
| PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) |
| "xxsubtype.spamlist", |
| sizeof(spamlistobject), |
| 0, |
| 0, /* tp_dealloc */ |
| 0, /* tp_print */ |
| 0, /* tp_getattr */ |
| 0, /* tp_setattr */ |
| 0, /* tp_reserved */ |
| 0, /* tp_repr */ |
| 0, /* tp_as_number */ |
| 0, /* tp_as_sequence */ |
| 0, /* tp_as_mapping */ |
| 0, /* tp_hash */ |
| 0, /* tp_call */ |
| 0, /* tp_str */ |
| 0, /* tp_getattro */ |
| 0, /* tp_setattro */ |
| 0, /* tp_as_buffer */ |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
| 0, /* tp_doc */ |
| 0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| 0, /* tp_richcompare */ |
| 0, /* tp_weaklistoffset */ |
| 0, /* tp_iter */ |
| 0, /* tp_iternext */ |
| spamlist_methods, /* tp_methods */ |
| 0, /* tp_members */ |
| spamlist_getsets, /* tp_getset */ |
| DEFERRED_ADDRESS(&PyList_Type), /* tp_base */ |
| 0, /* tp_dict */ |
| 0, /* tp_descr_get */ |
| 0, /* tp_descr_set */ |
| 0, /* tp_dictoffset */ |
| (initproc)spamlist_init, /* tp_init */ |
| 0, /* tp_alloc */ |
| 0, /* tp_new */ |
| }; |
| |
| /* spamdict -- a dict subtype */ |
| |
| typedef struct { |
| PyDictObject dict; |
| int state; |
| } spamdictobject; |
| |
| static PyObject * |
| spamdict_getstate(spamdictobject *self, PyObject *args) |
| { |
| if (!PyArg_ParseTuple(args, ":getstate")) |
| return NULL; |
| return PyLong_FromLong(self->state); |
| } |
| |
| static PyObject * |
| spamdict_setstate(spamdictobject *self, PyObject *args) |
| { |
| int state; |
| |
| if (!PyArg_ParseTuple(args, "i:setstate", &state)) |
| return NULL; |
| self->state = state; |
| Py_INCREF(Py_None); |
| return Py_None; |
| } |
| |
| static PyMethodDef spamdict_methods[] = { |
| {"getstate", (PyCFunction)spamdict_getstate, METH_VARARGS, |
| PyDoc_STR("getstate() -> state")}, |
| {"setstate", (PyCFunction)spamdict_setstate, METH_VARARGS, |
| PyDoc_STR("setstate(state)")}, |
| {NULL, NULL}, |
| }; |
| |
| static int |
| spamdict_init(spamdictobject *self, PyObject *args, PyObject *kwds) |
| { |
| if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0) |
| return -1; |
| self->state = 0; |
| return 0; |
| } |
| |
| static PyMemberDef spamdict_members[] = { |
| {"state", T_INT, offsetof(spamdictobject, state), READONLY, |
| PyDoc_STR("an int variable for demonstration purposes")}, |
| {0} |
| }; |
| |
| static PyTypeObject spamdict_type = { |
| PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0) |
| "xxsubtype.spamdict", |
| sizeof(spamdictobject), |
| 0, |
| 0, /* tp_dealloc */ |
| 0, /* tp_print */ |
| 0, /* tp_getattr */ |
| 0, /* tp_setattr */ |
| 0, /* tp_reserved */ |
| 0, /* tp_repr */ |
| 0, /* tp_as_number */ |
| 0, /* tp_as_sequence */ |
| 0, /* tp_as_mapping */ |
| 0, /* tp_hash */ |
| 0, /* tp_call */ |
| 0, /* tp_str */ |
| 0, /* tp_getattro */ |
| 0, /* tp_setattro */ |
| 0, /* tp_as_buffer */ |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
| 0, /* tp_doc */ |
| 0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| 0, /* tp_richcompare */ |
| 0, /* tp_weaklistoffset */ |
| 0, /* tp_iter */ |
| 0, /* tp_iternext */ |
| spamdict_methods, /* tp_methods */ |
| spamdict_members, /* tp_members */ |
| 0, /* tp_getset */ |
| DEFERRED_ADDRESS(&PyDict_Type), /* tp_base */ |
| 0, /* tp_dict */ |
| 0, /* tp_descr_get */ |
| 0, /* tp_descr_set */ |
| 0, /* tp_dictoffset */ |
| (initproc)spamdict_init, /* tp_init */ |
| 0, /* tp_alloc */ |
| 0, /* tp_new */ |
| }; |
| |
| static PyObject * |
| spam_bench(PyObject *self, PyObject *args) |
| { |
| PyObject *obj, *name, *res; |
| int n = 1000; |
| time_t t0, t1; |
| |
| if (!PyArg_ParseTuple(args, "OS|i", &obj, &name, &n)) |
| return NULL; |
| t0 = clock(); |
| while (--n >= 0) { |
| res = PyObject_GetAttr(obj, name); |
| if (res == NULL) |
| return NULL; |
| Py_DECREF(res); |
| } |
| t1 = clock(); |
| return PyFloat_FromDouble((double)(t1-t0) / CLOCKS_PER_SEC); |
| } |
| |
| static PyMethodDef xxsubtype_functions[] = { |
| {"bench", spam_bench, METH_VARARGS}, |
| {NULL, NULL} /* sentinel */ |
| }; |
| |
| static struct PyModuleDef xxsubtypemodule = { |
| PyModuleDef_HEAD_INIT, |
| "xxsubtype", |
| xxsubtype__doc__, |
| -1, |
| xxsubtype_functions, |
| NULL, |
| NULL, |
| NULL, |
| NULL |
| }; |
| |
| |
| PyMODINIT_FUNC |
| PyInit_xxsubtype(void) |
| { |
| PyObject *m; |
| |
| /* Fill in deferred data addresses. This must be done before |
| PyType_Ready() is called. Note that PyType_Ready() automatically |
| initializes the ob.ob_type field to &PyType_Type if it's NULL, |
| so it's not necessary to fill in ob_type first. */ |
| spamdict_type.tp_base = &PyDict_Type; |
| if (PyType_Ready(&spamdict_type) < 0) |
| return NULL; |
| |
| spamlist_type.tp_base = &PyList_Type; |
| if (PyType_Ready(&spamlist_type) < 0) |
| return NULL; |
| |
| m = PyModule_Create(&xxsubtypemodule); |
| if (m == NULL) |
| return NULL; |
| |
| if (PyType_Ready(&spamlist_type) < 0) |
| return NULL; |
| if (PyType_Ready(&spamdict_type) < 0) |
| return NULL; |
| |
| Py_INCREF(&spamlist_type); |
| if (PyModule_AddObject(m, "spamlist", |
| (PyObject *) &spamlist_type) < 0) |
| return NULL; |
| |
| Py_INCREF(&spamdict_type); |
| if (PyModule_AddObject(m, "spamdict", |
| (PyObject *) &spamdict_type) < 0) |
| return NULL; |
| return m; |
| } |