11#include "Python.h"
22#include "pycore_moduleobject.h" // _PyModule_GetState()
3+ #include "structmember.h"
34#include "clinic/_operator.c.h"
45
56typedef struct {
@@ -1478,14 +1479,33 @@ typedef struct {
14781479 PyObject * name ;
14791480 PyObject * args ;
14801481 PyObject * kwds ;
1482+ PyObject * * vectorcall_args ; /* Borrowed references */
1483+ PyObject * vectorcall_kwnames ;
1484+ vectorcallfunc vectorcall ;
14811485} methodcallerobject ;
14821486
1487+ static PyObject *
1488+ methodcaller_vectorcall (
1489+ methodcallerobject * mc , PyObject * const * args , size_t nargsf , PyObject * kwnames )
1490+ {
1491+ if (!_PyArg_CheckPositional ("methodcaller" , PyVectorcall_NARGS (nargsf ), 1 , 1 )
1492+ || !_PyArg_NoKwnames ("methodcaller" , kwnames )) {
1493+ return NULL ;
1494+ }
1495+ mc -> vectorcall_args [0 ] = args [0 ];
1496+ return PyObject_VectorcallMethod (
1497+ mc -> name , mc -> vectorcall_args ,
1498+ (1 + PyTuple_GET_SIZE (mc -> args )) | PY_VECTORCALL_ARGUMENTS_OFFSET ,
1499+ mc -> vectorcall_kwnames );
1500+ }
1501+
14831502/* AC 3.5: variable number of arguments, not currently support by AC */
14841503static PyObject *
14851504methodcaller_new (PyTypeObject * type , PyObject * args , PyObject * kwds )
14861505{
14871506 methodcallerobject * mc ;
1488- PyObject * name ;
1507+ PyObject * name , * key , * value ;
1508+ Py_ssize_t nargs , i , ppos ;
14891509
14901510 if (PyTuple_GET_SIZE (args ) < 1 ) {
14911511 PyErr_SetString (PyExc_TypeError , "methodcaller needs at least "
@@ -1521,6 +1541,32 @@ methodcaller_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
15211541 return NULL ;
15221542 }
15231543
1544+ nargs = PyTuple_GET_SIZE (args ) - 1 ;
1545+ mc -> vectorcall_args = PyMem_Calloc (
1546+ 1 + nargs + (kwds ? PyDict_Size (kwds ) : 0 ),
1547+ sizeof (PyObject * ));
1548+ if (!mc -> vectorcall_args ) {
1549+ return PyErr_NoMemory ();
1550+ }
1551+ /* The first item of vectorcall_args will be filled with obj. */
1552+ memcpy (mc -> vectorcall_args + 1 , PySequence_Fast_ITEMS (mc -> args ),
1553+ nargs * sizeof (PyObject * ));
1554+ if (kwds ) {
1555+ mc -> vectorcall_kwnames = PySequence_Tuple (kwds );
1556+ if (!mc -> vectorcall_kwnames ) {
1557+ return NULL ;
1558+ }
1559+ i = ppos = 0 ;
1560+ while (PyDict_Next (kwds , & ppos , & key , & value )) {
1561+ mc -> vectorcall_args [1 + nargs + i ] = value ;
1562+ ++ i ;
1563+ }
1564+ }
1565+ else {
1566+ mc -> vectorcall_kwnames = NULL ;
1567+ }
1568+ mc -> vectorcall = (vectorcallfunc )methodcaller_vectorcall ;
1569+
15241570 PyObject_GC_Track (mc );
15251571 return (PyObject * )mc ;
15261572}
@@ -1531,6 +1577,7 @@ methodcaller_clear(methodcallerobject *mc)
15311577 Py_CLEAR (mc -> name );
15321578 Py_CLEAR (mc -> args );
15331579 Py_CLEAR (mc -> kwds );
1580+ Py_CLEAR (mc -> vectorcall_kwnames );
15341581 return 0 ;
15351582}
15361583
@@ -1540,6 +1587,7 @@ methodcaller_dealloc(methodcallerobject *mc)
15401587 PyTypeObject * tp = Py_TYPE (mc );
15411588 PyObject_GC_UnTrack (mc );
15421589 (void )methodcaller_clear (mc );
1590+ PyMem_Free (mc -> vectorcall_args );
15431591 tp -> tp_free (mc );
15441592 Py_DECREF (tp );
15451593}
@@ -1696,6 +1744,12 @@ static PyMethodDef methodcaller_methods[] = {
16961744 reduce_doc },
16971745 {NULL }
16981746};
1747+
1748+ static PyMemberDef methodcaller_members [] = {
1749+ {"__vectorcalloffset__" , T_PYSSIZET , offsetof(methodcallerobject , vectorcall ), READONLY },
1750+ {NULL }
1751+ };
1752+
16991753PyDoc_STRVAR (methodcaller_doc ,
17001754"methodcaller(name, ...) --> methodcaller object\n\
17011755\n\
@@ -1711,6 +1765,7 @@ static PyType_Slot methodcaller_type_slots[] = {
17111765 {Py_tp_traverse , methodcaller_traverse },
17121766 {Py_tp_clear , methodcaller_clear },
17131767 {Py_tp_methods , methodcaller_methods },
1768+ {Py_tp_members , methodcaller_members },
17141769 {Py_tp_new , methodcaller_new },
17151770 {Py_tp_getattro , PyObject_GenericGetAttr },
17161771 {Py_tp_repr , methodcaller_repr },
@@ -1722,7 +1777,7 @@ static PyType_Spec methodcaller_type_spec = {
17221777 .basicsize = sizeof (methodcallerobject ),
17231778 .itemsize = 0 ,
17241779 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1725- Py_TPFLAGS_IMMUTABLETYPE ),
1780+ Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_IMMUTABLETYPE ),
17261781 .slots = methodcaller_type_slots ,
17271782};
17281783
0 commit comments