(root)/
Python-3.12.0/
Modules/
_testcapi/
vectorcall_limited.c
       1  #define Py_LIMITED_API 0x030c0000 // 3.12
       2  #include "parts.h"
       3  
       4  #ifdef LIMITED_API_AVAILABLE
       5  
       6  #include "structmember.h"         // PyMemberDef
       7  
       8  /* Test Vectorcall in the limited API */
       9  
      10  static PyObject *
      11  LimitedVectorCallClass_tpcall(PyObject *self, PyObject *args, PyObject *kwargs) {
      12      return PyUnicode_FromString("tp_call called");
      13  }
      14  
      15  static PyObject *
      16  LimitedVectorCallClass_vectorcall(PyObject *callable,
      17                              PyObject *const *args,
      18                              size_t nargsf,
      19                              PyObject *kwnames) {
      20      return PyUnicode_FromString("vectorcall called");
      21  }
      22  
      23  static PyObject *
      24  LimitedVectorCallClass_new(PyTypeObject *tp, PyTypeObject *a, PyTypeObject *kw)
      25  {
      26      PyObject *self = ((allocfunc)PyType_GetSlot(tp, Py_tp_alloc))(tp, 0);
      27      if (!self) {
      28          return NULL;
      29      }
      30      *(vectorcallfunc*)((char*)self + sizeof(PyObject)) = (
      31          LimitedVectorCallClass_vectorcall);
      32      return self;
      33  }
      34  
      35  static PyObject *
      36  call_vectorcall(PyObject* self, PyObject *callable)
      37  {
      38      PyObject *args[3] = { NULL, NULL, NULL };
      39      PyObject *kwname = NULL, *kwnames = NULL, *result = NULL;
      40  
      41      args[1] = PyUnicode_FromString("foo");
      42      if (!args[1]) {
      43          goto leave;
      44      }
      45  
      46      args[2] = PyUnicode_FromString("bar");
      47      if (!args[2]) {
      48          goto leave;
      49      }
      50  
      51      kwname = PyUnicode_InternFromString("baz");
      52      if (!kwname) {
      53          goto leave;
      54      }
      55  
      56      kwnames = PyTuple_New(1);
      57      if (!kwnames) {
      58          goto leave;
      59      }
      60  
      61      if (PyTuple_SetItem(kwnames, 0, kwname)) {
      62          goto leave;
      63      }
      64  
      65      result = PyObject_Vectorcall(
      66          callable,
      67          args + 1,
      68          1 | PY_VECTORCALL_ARGUMENTS_OFFSET,
      69          kwnames
      70      );
      71  
      72  leave:
      73      Py_XDECREF(args[1]);
      74      Py_XDECREF(args[2]);
      75      Py_XDECREF(kwnames);
      76  
      77      return result;
      78  }
      79  
      80  static PyObject *
      81  call_vectorcall_method(PyObject* self, PyObject *callable)
      82  {
      83      PyObject *args[3] = { NULL, NULL, NULL };
      84      PyObject *name = NULL, *kwname = NULL,
      85               *kwnames = NULL, *result = NULL;
      86  
      87      name = PyUnicode_FromString("f");
      88      if (!name) {
      89          goto leave;
      90      }
      91  
      92      args[0] = callable;
      93      args[1] = PyUnicode_FromString("foo");
      94      if (!args[1]) {
      95          goto leave;
      96      }
      97  
      98      args[2] = PyUnicode_FromString("bar");
      99      if (!args[2]) {
     100          goto leave;
     101      }
     102  
     103      kwname = PyUnicode_InternFromString("baz");
     104      if (!kwname) {
     105          goto leave;
     106      }
     107  
     108      kwnames = PyTuple_New(1);
     109      if (!kwnames) {
     110          goto leave;
     111      }
     112  
     113      if (PyTuple_SetItem(kwnames, 0, kwname)) {
     114          goto leave;
     115      }
     116  
     117  
     118      result = PyObject_VectorcallMethod(
     119          name,
     120          args,
     121          2 | PY_VECTORCALL_ARGUMENTS_OFFSET,
     122          kwnames
     123      );
     124  
     125  leave:
     126      Py_XDECREF(name);
     127      Py_XDECREF(args[1]);
     128      Py_XDECREF(args[2]);
     129      Py_XDECREF(kwnames);
     130  
     131      return result;
     132  }
     133  
     134  static PyMemberDef LimitedVectorCallClass_members[] = {
     135      {"__vectorcalloffset__", T_PYSSIZET, sizeof(PyObject), READONLY},
     136      {NULL}
     137  };
     138  
     139  static PyType_Slot LimitedVectorallClass_slots[] = {
     140      {Py_tp_new, LimitedVectorCallClass_new},
     141      {Py_tp_call, LimitedVectorCallClass_tpcall},
     142      {Py_tp_members, LimitedVectorCallClass_members},
     143      {0},
     144  };
     145  
     146  static PyType_Spec LimitedVectorCallClass_spec = {
     147      .name = "_testcapi.LimitedVectorCallClass",
     148      .basicsize = (int)(sizeof(PyObject) + sizeof(vectorcallfunc)),
     149      .flags = Py_TPFLAGS_DEFAULT
     150          | Py_TPFLAGS_HAVE_VECTORCALL
     151          | Py_TPFLAGS_BASETYPE,
     152      .slots = LimitedVectorallClass_slots,
     153  };
     154  
     155  static PyMethodDef TestMethods[] = {
     156      {"call_vectorcall", call_vectorcall, METH_O},
     157      {"call_vectorcall_method", call_vectorcall_method, METH_O},
     158      {NULL},
     159  };
     160  
     161  int
     162  _PyTestCapi_Init_VectorcallLimited(PyObject *m) {
     163      if (PyModule_AddFunctions(m, TestMethods) < 0) {
     164          return -1;
     165      }
     166  
     167      PyObject *LimitedVectorCallClass = PyType_FromModuleAndSpec(
     168          m, &LimitedVectorCallClass_spec, NULL);
     169      if (!LimitedVectorCallClass) {
     170          return -1;
     171      }
     172      if (PyModule_AddType(m, (PyTypeObject *)LimitedVectorCallClass) < 0) {
     173          return -1;
     174      }
     175  
     176      return 0;
     177  }
     178  
     179  #endif // LIMITED_API_AVAILABLE