(root)/
Python-3.11.7/
Modules/
xxsubtype.c
       1  #include "Python.h"
       2  #include "structmember.h"         // PyMemberDef
       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_CAST(spamlist_specialmeth),
      74          METH_VARARGS | METH_KEYWORDS | METH_CLASS,
      75          PyDoc_STR("classmeth(*args, **kw)")},
      76      {"staticmeth", _PyCFunction_CAST(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, void *Py_UNUSED(ignored))
      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_vectorcall_offset */
     110      0,                                          /* tp_getattr */
     111      0,                                          /* tp_setattr */
     112      0,                                          /* tp_as_async */
     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_vectorcall_offset */
     201      0,                                          /* tp_getattr */
     202      0,                                          /* tp_setattr */
     203      0,                                          /* tp_as_async */
     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 = 0, t1 = 0;
     241  
     242      if (!PyArg_ParseTuple(args, "OU|i", &obj, &name, &n))
     243          return NULL;
     244  #ifdef HAVE_CLOCK
     245      t0 = clock();
     246      while (--n >= 0) {
     247          res = PyObject_GetAttr(obj, name);
     248          if (res == NULL)
     249              return NULL;
     250          Py_DECREF(res);
     251      }
     252      t1 = clock();
     253  #endif
     254      return PyFloat_FromDouble((double)(t1-t0) / CLOCKS_PER_SEC);
     255  }
     256  
     257  static PyMethodDef xxsubtype_functions[] = {
     258      {"bench",           spam_bench,     METH_VARARGS},
     259      {NULL,              NULL}           /* sentinel */
     260  };
     261  
     262  static int
     263  xxsubtype_exec(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 -1;
     272  
     273      spamlist_type.tp_base = &PyList_Type;
     274      if (PyType_Ready(&spamlist_type) < 0)
     275          return -1;
     276  
     277      if (PyType_Ready(&spamlist_type) < 0)
     278          return -1;
     279      if (PyType_Ready(&spamdict_type) < 0)
     280          return -1;
     281  
     282      if (PyModule_AddObjectRef(m, "spamlist",
     283                                (PyObject *) &spamlist_type) < 0)
     284          return -1;
     285  
     286      if (PyModule_AddObjectRef(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  }