11#include "Python.h"
22#include "pycore_moduleobject.h" // _PyModule_GetState()
3+ #include "structmember.h" // PyMemberDef
34#include "pycore_runtime.h" // _Py_ID()
45#include "clinic/_operator.c.h"
56
@@ -974,8 +975,15 @@ typedef struct {
974975 Py_ssize_t nitems ;
975976 PyObject * item ;
976977 Py_ssize_t index ; // -1 unless *item* is a single non-negative integer index
978+ vectorcallfunc vectorcall ;
977979} itemgetterobject ;
978980
981+ // Forward declarations
982+ static PyObject *
983+ itemgetter_vectorcall (PyObject * , PyObject * const * , size_t , PyObject * );
984+ static PyObject *
985+ itemgetter_call_impl (itemgetterobject * , PyObject * );
986+
979987/* AC 3.5: treats first argument as an iterable, otherwise uses *args */
980988static PyObject *
981989itemgetter_new (PyTypeObject * type , PyObject * args , PyObject * kwds )
@@ -1021,6 +1029,7 @@ itemgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
10211029 }
10221030 }
10231031
1032+ ig -> vectorcall = (vectorcallfunc )itemgetter_vectorcall ;
10241033 PyObject_GC_Track (ig );
10251034 return (PyObject * )ig ;
10261035}
@@ -1053,16 +1062,33 @@ itemgetter_traverse(itemgetterobject *ig, visitproc visit, void *arg)
10531062static PyObject *
10541063itemgetter_call (itemgetterobject * ig , PyObject * args , PyObject * kw )
10551064{
1056- PyObject * obj , * result ;
1057- Py_ssize_t i , nitems = ig -> nitems ;
1058-
10591065 assert (PyTuple_CheckExact (args ));
10601066 if (!_PyArg_NoKeywords ("itemgetter" , kw ))
10611067 return NULL ;
10621068 if (!_PyArg_CheckPositional ("itemgetter" , PyTuple_GET_SIZE (args ), 1 , 1 ))
10631069 return NULL ;
1070+ return itemgetter_call_impl (ig , PyTuple_GET_ITEM (args , 0 ));
1071+ }
10641072
1065- obj = PyTuple_GET_ITEM (args , 0 );
1073+ static PyObject *
1074+ itemgetter_vectorcall (PyObject * ig , PyObject * const * args ,
1075+ size_t nargsf , PyObject * kwnames )
1076+ {
1077+ if (!_PyArg_NoKwnames ("itemgetter" , kwnames )) {
1078+ return NULL ;
1079+ }
1080+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
1081+ if (!_PyArg_CheckPositional ("itemgetter" , nargs , 1 , 1 )) {
1082+ return NULL ;
1083+ }
1084+ return itemgetter_call_impl ((itemgetterobject * )ig , args [0 ]);
1085+ }
1086+
1087+ static PyObject *
1088+ itemgetter_call_impl (itemgetterobject * ig , PyObject * obj )
1089+ {
1090+ PyObject * result ;
1091+ Py_ssize_t i , nitems = ig -> nitems ;
10661092 if (nitems == 1 ) {
10671093 if (ig -> index >= 0
10681094 && PyTuple_CheckExact (obj )
@@ -1130,6 +1156,11 @@ static PyMethodDef itemgetter_methods[] = {
11301156 {NULL }
11311157};
11321158
1159+ static PyMemberDef itemgetter_members [] = {
1160+ {"__vectorcalloffset__" , T_PYSSIZET , offsetof(itemgetterobject , vectorcall ), READONLY },
1161+ {NULL } /* Sentinel */
1162+ };
1163+
11331164PyDoc_STRVAR (itemgetter_doc ,
11341165"itemgetter(item, ...) --> itemgetter object\n\
11351166\n\
@@ -1144,6 +1175,7 @@ static PyType_Slot itemgetter_type_slots[] = {
11441175 {Py_tp_traverse , itemgetter_traverse },
11451176 {Py_tp_clear , itemgetter_clear },
11461177 {Py_tp_methods , itemgetter_methods },
1178+ {Py_tp_members , itemgetter_members },
11471179 {Py_tp_new , itemgetter_new },
11481180 {Py_tp_getattro , PyObject_GenericGetAttr },
11491181 {Py_tp_repr , itemgetter_repr },
@@ -1155,7 +1187,7 @@ static PyType_Spec itemgetter_type_spec = {
11551187 .basicsize = sizeof (itemgetterobject ),
11561188 .itemsize = 0 ,
11571189 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1158- Py_TPFLAGS_IMMUTABLETYPE ),
1190+ Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_VECTORCALL ),
11591191 .slots = itemgetter_type_slots ,
11601192};
11611193
@@ -1165,8 +1197,15 @@ typedef struct {
11651197 PyObject_HEAD
11661198 Py_ssize_t nattrs ;
11671199 PyObject * attr ;
1200+ vectorcallfunc vectorcall ;
11681201} attrgetterobject ;
11691202
1203+ // Forward declarations
1204+ static PyObject *
1205+ attrgetter_vectorcall (PyObject * , PyObject * const * , size_t , PyObject * );
1206+ static PyObject *
1207+ attrgetter_call_impl (attrgetterobject * , PyObject * );
1208+
11701209/* AC 3.5: treats first argument as an iterable, otherwise uses *args */
11711210static PyObject *
11721211attrgetter_new (PyTypeObject * type , PyObject * args , PyObject * kwds )
@@ -1210,7 +1249,7 @@ attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
12101249 kind = PyUnicode_KIND (item );
12111250 data = PyUnicode_DATA (item );
12121251
1213- /* check whethere the string is dotted */
1252+ /* check whether the string is dotted */
12141253 dot_count = 0 ;
12151254 for (char_idx = 0 ; char_idx < item_len ; ++ char_idx ) {
12161255 if (PyUnicode_READ (kind , data , char_idx ) == '.' )
@@ -1276,6 +1315,7 @@ attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
12761315
12771316 ag -> attr = attr ;
12781317 ag -> nattrs = nattrs ;
1318+ ag -> vectorcall = (vectorcallfunc )attrgetter_vectorcall ;
12791319
12801320 PyObject_GC_Track (ag );
12811321 return (PyObject * )ag ;
@@ -1342,16 +1382,36 @@ dotted_getattr(PyObject *obj, PyObject *attr)
13421382static PyObject *
13431383attrgetter_call (attrgetterobject * ag , PyObject * args , PyObject * kw )
13441384{
1345- PyObject * obj , * result ;
1346- Py_ssize_t i , nattrs = ag -> nattrs ;
1347-
13481385 if (!_PyArg_NoKeywords ("attrgetter" , kw ))
13491386 return NULL ;
13501387 if (!_PyArg_CheckPositional ("attrgetter" , PyTuple_GET_SIZE (args ), 1 , 1 ))
13511388 return NULL ;
1352- obj = PyTuple_GET_ITEM (args , 0 );
1353- if (ag -> nattrs == 1 ) /* ag->attr is always a tuple */
1389+ return attrgetter_call_impl (ag , PyTuple_GET_ITEM (args , 0 ));
1390+ }
1391+
1392+ static PyObject *
1393+ attrgetter_vectorcall (PyObject * ag , PyObject * const * args , size_t nargsf , PyObject * kwnames )
1394+ {
1395+ if (!_PyArg_NoKwnames ("attrgetter" , kwnames )) {
1396+ return NULL ;
1397+ }
1398+ Py_ssize_t nargs = PyVectorcall_NARGS (nargsf );
1399+ if (!_PyArg_CheckPositional ("attrgetter" , nargs , 1 , 1 )) {
1400+ return NULL ;
1401+ }
1402+ return attrgetter_call_impl ((attrgetterobject * )ag , args [0 ]);
1403+ }
1404+
1405+ static PyObject *
1406+ attrgetter_call_impl (attrgetterobject * ag , PyObject * obj )
1407+ {
1408+ PyObject * result ;
1409+ Py_ssize_t i , nattrs = ag -> nattrs ;
1410+
1411+ if (ag -> nattrs == 1 ) {
1412+ /* ag->attr is always a tuple */
13541413 return dotted_getattr (obj , PyTuple_GET_ITEM (ag -> attr , 0 ));
1414+ }
13551415
13561416 assert (PyTuple_Check (ag -> attr ));
13571417 assert (PyTuple_GET_SIZE (ag -> attr ) == nattrs );
@@ -1460,6 +1520,11 @@ static PyMethodDef attrgetter_methods[] = {
14601520 {NULL }
14611521};
14621522
1523+ static PyMemberDef attrgetter_members [] = {
1524+ {"__vectorcalloffset__" , T_PYSSIZET , offsetof(attrgetterobject , vectorcall ), READONLY },
1525+ {NULL } /* Sentinel*/
1526+ };
1527+
14631528PyDoc_STRVAR (attrgetter_doc ,
14641529"attrgetter(attr, ...) --> attrgetter object\n\
14651530\n\
@@ -1476,6 +1541,7 @@ static PyType_Slot attrgetter_type_slots[] = {
14761541 {Py_tp_traverse , attrgetter_traverse },
14771542 {Py_tp_clear , attrgetter_clear },
14781543 {Py_tp_methods , attrgetter_methods },
1544+ {Py_tp_members , attrgetter_members },
14791545 {Py_tp_new , attrgetter_new },
14801546 {Py_tp_getattro , PyObject_GenericGetAttr },
14811547 {Py_tp_repr , attrgetter_repr },
@@ -1487,7 +1553,7 @@ static PyType_Spec attrgetter_type_spec = {
14871553 .basicsize = sizeof (attrgetterobject ),
14881554 .itemsize = 0 ,
14891555 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1490- Py_TPFLAGS_IMMUTABLETYPE ),
1556+ Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_VECTORCALL ),
14911557 .slots = attrgetter_type_slots ,
14921558};
14931559
0 commit comments