/Modules/xxsubtype.c
http://unladen-swallow.googlecode.com/ · C · 297 lines · 249 code · 33 blank · 15 comment · 24 complexity · 7acbd3f69b7dfc23a539c1e546f5040d MD5 · raw file
- #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 PyInt_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 PyInt_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_compare */
- 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 PyInt_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_compare */
- 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 */
- };
- PyMODINIT_FUNC
- initxxsubtype(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;
- spamlist_type.tp_base = &PyList_Type;
- if (PyType_Ready(&spamlist_type) < 0)
- return;
- m = Py_InitModule3("xxsubtype",
- xxsubtype_functions,
- xxsubtype__doc__);
- if (m == NULL)
- return;
- if (PyType_Ready(&spamlist_type) < 0)
- return;
- if (PyType_Ready(&spamdict_type) < 0)
- return;
- Py_INCREF(&spamlist_type);
- if (PyModule_AddObject(m, "spamlist",
- (PyObject *) &spamlist_type) < 0)
- return;
- Py_INCREF(&spamdict_type);
- if (PyModule_AddObject(m, "spamdict",
- (PyObject *) &spamdict_type) < 0)
- return;
- }