(root)/
Python-3.12.0/
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      return Py_NewRef(Py_None);
      43  }
      44  
      45  static PyObject *
      46  spamlist_specialmeth(PyObject *self, PyObject *args, PyObject *kw)
      47  {
      48      PyObject *result = PyTuple_New(3);
      49  
      50      if (result != NULL) {
      51          if (self == NULL)
      52              self = Py_None;
      53          if (kw == NULL)
      54              kw = Py_None;
      55          PyTuple_SET_ITEM(result, 0, Py_NewRef(self));
      56          PyTuple_SET_ITEM(result, 1, Py_NewRef(args));
      57          PyTuple_SET_ITEM(result, 2, Py_NewRef(kw));
      58      }
      59      return result;
      60  }
      61  
      62  static PyMethodDef spamlist_methods[] = {
      63      {"getstate", (PyCFunction)spamlist_getstate, METH_VARARGS,
      64          PyDoc_STR("getstate() -> state")},
      65      {"setstate", (PyCFunction)spamlist_setstate, METH_VARARGS,
      66          PyDoc_STR("setstate(state)")},
      67      /* These entries differ only in the flags; they are used by the tests
      68         in test.test_descr. */
      69      {"classmeth", _PyCFunction_CAST(spamlist_specialmeth),
      70          METH_VARARGS | METH_KEYWORDS | METH_CLASS,
      71          PyDoc_STR("classmeth(*args, **kw)")},
      72      {"staticmeth", _PyCFunction_CAST(spamlist_specialmeth),
      73          METH_VARARGS | METH_KEYWORDS | METH_STATIC,
      74          PyDoc_STR("staticmeth(*args, **kw)")},
      75      {NULL,      NULL},
      76  };
      77  
      78  static int
      79  spamlist_init(spamlistobject *self, PyObject *args, PyObject *kwds)
      80  {
      81      if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0)
      82          return -1;
      83      self->state = 0;
      84      return 0;
      85  }
      86  
      87  static PyObject *
      88  spamlist_state_get(spamlistobject *self, void *Py_UNUSED(ignored))
      89  {
      90      return PyLong_FromLong(self->state);
      91  }
      92  
      93  static PyGetSetDef spamlist_getsets[] = {
      94      {"state", (getter)spamlist_state_get, NULL,
      95       PyDoc_STR("an int variable for demonstration purposes")},
      96      {0}
      97  };
      98  
      99  static PyTypeObject spamlist_type = {
     100      PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
     101      "xxsubtype.spamlist",
     102      sizeof(spamlistobject),
     103      0,
     104      0,                                          /* tp_dealloc */
     105      0,                                          /* tp_vectorcall_offset */
     106      0,                                          /* tp_getattr */
     107      0,                                          /* tp_setattr */
     108      0,                                          /* tp_as_async */
     109      0,                                          /* tp_repr */
     110      0,                                          /* tp_as_number */
     111      0,                                          /* tp_as_sequence */
     112      0,                                          /* tp_as_mapping */
     113      0,                                          /* tp_hash */
     114      0,                                          /* tp_call */
     115      0,                                          /* tp_str */
     116      0,                                          /* tp_getattro */
     117      0,                                          /* tp_setattro */
     118      0,                                          /* tp_as_buffer */
     119      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
     120      0,                                          /* tp_doc */
     121      0,                                          /* tp_traverse */
     122      0,                                          /* tp_clear */
     123      0,                                          /* tp_richcompare */
     124      0,                                          /* tp_weaklistoffset */
     125      0,                                          /* tp_iter */
     126      0,                                          /* tp_iternext */
     127      spamlist_methods,                           /* tp_methods */
     128      0,                                          /* tp_members */
     129      spamlist_getsets,                           /* tp_getset */
     130      DEFERRED_ADDRESS(&PyList_Type),             /* tp_base */
     131      0,                                          /* tp_dict */
     132      0,                                          /* tp_descr_get */
     133      0,                                          /* tp_descr_set */
     134      0,                                          /* tp_dictoffset */
     135      (initproc)spamlist_init,                    /* tp_init */
     136      0,                                          /* tp_alloc */
     137      0,                                          /* tp_new */
     138  };
     139  
     140  /* spamdict -- a dict subtype */
     141  
     142  typedef struct {
     143      PyDictObject dict;
     144      int state;
     145  } spamdictobject;
     146  
     147  static PyObject *
     148  spamdict_getstate(spamdictobject *self, PyObject *args)
     149  {
     150      if (!PyArg_ParseTuple(args, ":getstate"))
     151          return NULL;
     152      return PyLong_FromLong(self->state);
     153  }
     154  
     155  static PyObject *
     156  spamdict_setstate(spamdictobject *self, PyObject *args)
     157  {
     158      int state;
     159  
     160      if (!PyArg_ParseTuple(args, "i:setstate", &state))
     161          return NULL;
     162      self->state = state;
     163      return Py_NewRef(Py_None);
     164  }
     165  
     166  static PyMethodDef spamdict_methods[] = {
     167      {"getstate", (PyCFunction)spamdict_getstate, METH_VARARGS,
     168          PyDoc_STR("getstate() -> state")},
     169      {"setstate", (PyCFunction)spamdict_setstate, METH_VARARGS,
     170          PyDoc_STR("setstate(state)")},
     171      {NULL,      NULL},
     172  };
     173  
     174  static int
     175  spamdict_init(spamdictobject *self, PyObject *args, PyObject *kwds)
     176  {
     177      if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
     178          return -1;
     179      self->state = 0;
     180      return 0;
     181  }
     182  
     183  static PyMemberDef spamdict_members[] = {
     184      {"state", T_INT, offsetof(spamdictobject, state), READONLY,
     185       PyDoc_STR("an int variable for demonstration purposes")},
     186      {0}
     187  };
     188  
     189  static PyTypeObject spamdict_type = {
     190      PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
     191      "xxsubtype.spamdict",
     192      sizeof(spamdictobject),
     193      0,
     194      0,                                          /* tp_dealloc */
     195      0,                                          /* tp_vectorcall_offset */
     196      0,                                          /* tp_getattr */
     197      0,                                          /* tp_setattr */
     198      0,                                          /* tp_as_async */
     199      0,                                          /* tp_repr */
     200      0,                                          /* tp_as_number */
     201      0,                                          /* tp_as_sequence */
     202      0,                                          /* tp_as_mapping */
     203      0,                                          /* tp_hash */
     204      0,                                          /* tp_call */
     205      0,                                          /* tp_str */
     206      0,                                          /* tp_getattro */
     207      0,                                          /* tp_setattro */
     208      0,                                          /* tp_as_buffer */
     209      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
     210      0,                                          /* tp_doc */
     211      0,                                          /* tp_traverse */
     212      0,                                          /* tp_clear */
     213      0,                                          /* tp_richcompare */
     214      0,                                          /* tp_weaklistoffset */
     215      0,                                          /* tp_iter */
     216      0,                                          /* tp_iternext */
     217      spamdict_methods,                           /* tp_methods */
     218      spamdict_members,                           /* tp_members */
     219      0,                                          /* tp_getset */
     220      DEFERRED_ADDRESS(&PyDict_Type),             /* tp_base */
     221      0,                                          /* tp_dict */
     222      0,                                          /* tp_descr_get */
     223      0,                                          /* tp_descr_set */
     224      0,                                          /* tp_dictoffset */
     225      (initproc)spamdict_init,                    /* tp_init */
     226      0,                                          /* tp_alloc */
     227      0,                                          /* tp_new */
     228  };
     229  
     230  static PyObject *
     231  spam_bench(PyObject *self, PyObject *args)
     232  {
     233      PyObject *obj, *name, *res;
     234      int n = 1000;
     235      time_t t0 = 0, t1 = 0;
     236  
     237      if (!PyArg_ParseTuple(args, "OU|i", &obj, &name, &n))
     238          return NULL;
     239  #ifdef HAVE_CLOCK
     240      t0 = clock();
     241      while (--n >= 0) {
     242          res = PyObject_GetAttr(obj, name);
     243          if (res == NULL)
     244              return NULL;
     245          Py_DECREF(res);
     246      }
     247      t1 = clock();
     248  #endif
     249      return PyFloat_FromDouble((double)(t1-t0) / CLOCKS_PER_SEC);
     250  }
     251  
     252  static PyMethodDef xxsubtype_functions[] = {
     253      {"bench",           spam_bench,     METH_VARARGS},
     254      {NULL,              NULL}           /* sentinel */
     255  };
     256  
     257  static int
     258  xxsubtype_exec(PyObject* m)
     259  {
     260      /* Fill in deferred data addresses.  This must be done before
     261         PyType_Ready() is called.  Note that PyType_Ready() automatically
     262         initializes the ob.ob_type field to &PyType_Type if it's NULL,
     263         so it's not necessary to fill in ob_type first. */
     264      spamdict_type.tp_base = &PyDict_Type;
     265      if (PyType_Ready(&spamdict_type) < 0)
     266          return -1;
     267  
     268      spamlist_type.tp_base = &PyList_Type;
     269      if (PyType_Ready(&spamlist_type) < 0)
     270          return -1;
     271  
     272      if (PyType_Ready(&spamlist_type) < 0)
     273          return -1;
     274      if (PyType_Ready(&spamdict_type) < 0)
     275          return -1;
     276  
     277      if (PyModule_AddObjectRef(m, "spamlist", (PyObject *)&spamlist_type) < 0)
     278          return -1;
     279  
     280      if (PyModule_AddObjectRef(m, "spamdict", (PyObject *)&spamdict_type) < 0)
     281          return -1;
     282      return 0;
     283  }
     284  
     285  static struct PyModuleDef_Slot xxsubtype_slots[] = {
     286      {Py_mod_exec, xxsubtype_exec},
     287      {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
     288      {0, NULL},
     289  };
     290  
     291  static struct PyModuleDef xxsubtypemodule = {
     292      PyModuleDef_HEAD_INIT,
     293      "xxsubtype",
     294      xxsubtype__doc__,
     295      0,
     296      xxsubtype_functions,
     297      xxsubtype_slots,
     298      NULL,
     299      NULL,
     300      NULL
     301  };
     302  
     303  
     304  PyMODINIT_FUNC
     305  PyInit_xxsubtype(void)
     306  {
     307      return PyModuleDef_Init(&xxsubtypemodule);
     308  }