You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
7.8 KiB
303 lines
7.8 KiB
#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 PyTypeObject spamlist_type; |
|
|
|
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 = { |
|
PyObject_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 PyTypeObject spamdict_type; |
|
|
|
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 = { |
|
PyObject_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; |
|
}
|
|
|