Home | History | Annotate | Download | only in Modules
      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 PyLong_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 PyLong_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_reserved */
    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 PyLong_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_reserved */
    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 static int
    261 xxsubtype_exec(PyObject* m)
    262 {
    263     /* Fill in deferred data addresses.  This must be done before
    264        PyType_Ready() is called.  Note that PyType_Ready() automatically
    265        initializes the ob.ob_type field to &PyType_Type if it's NULL,
    266        so it's not necessary to fill in ob_type first. */
    267     spamdict_type.tp_base = &PyDict_Type;
    268     if (PyType_Ready(&spamdict_type) < 0)
    269         return -1;
    270 
    271     spamlist_type.tp_base = &PyList_Type;
    272     if (PyType_Ready(&spamlist_type) < 0)
    273         return -1;
    274 
    275     if (PyType_Ready(&spamlist_type) < 0)
    276         return -1;
    277     if (PyType_Ready(&spamdict_type) < 0)
    278         return -1;
    279 
    280     Py_INCREF(&spamlist_type);
    281     if (PyModule_AddObject(m, "spamlist",
    282                            (PyObject *) &spamlist_type) < 0)
    283         return -1;
    284 
    285     Py_INCREF(&spamdict_type);
    286     if (PyModule_AddObject(m, "spamdict",
    287                            (PyObject *) &spamdict_type) < 0)
    288         return -1;
    289     return 0;
    290 }
    291 
    292 static struct PyModuleDef_Slot xxsubtype_slots[] = {
    293     {Py_mod_exec, xxsubtype_exec},
    294     {0, NULL},
    295 };
    296 
    297 static struct PyModuleDef xxsubtypemodule = {
    298     PyModuleDef_HEAD_INIT,
    299     "xxsubtype",
    300     xxsubtype__doc__,
    301     0,
    302     xxsubtype_functions,
    303     xxsubtype_slots,
    304     NULL,
    305     NULL,
    306     NULL
    307 };
    308 
    309 
    310 PyMODINIT_FUNC
    311 PyInit_xxsubtype(void)
    312 {
    313     return PyModuleDef_Init(&xxsubtypemodule);
    314 }
    315