1
1
#include "Python.h"
2
2
#include "pycore_moduleobject.h" // _PyModule_GetState()
3
+ #include "structmember.h" // PyMemberDef
3
4
#include "pycore_runtime.h" // _Py_ID()
4
5
#include "clinic/_operator.c.h"
5
6
@@ -974,8 +975,15 @@ typedef struct {
974
975
Py_ssize_t nitems ;
975
976
PyObject * item ;
976
977
Py_ssize_t index ; // -1 unless *item* is a single non-negative integer index
978
+ vectorcallfunc vectorcall ;
977
979
} itemgetterobject ;
978
980
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
+
979
987
/* AC 3.5: treats first argument as an iterable, otherwise uses *args */
980
988
static PyObject *
981
989
itemgetter_new (PyTypeObject * type , PyObject * args , PyObject * kwds )
@@ -1021,6 +1029,7 @@ itemgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1021
1029
}
1022
1030
}
1023
1031
1032
+ ig -> vectorcall = (vectorcallfunc )itemgetter_vectorcall ;
1024
1033
PyObject_GC_Track (ig );
1025
1034
return (PyObject * )ig ;
1026
1035
}
@@ -1053,16 +1062,33 @@ itemgetter_traverse(itemgetterobject *ig, visitproc visit, void *arg)
1053
1062
static PyObject *
1054
1063
itemgetter_call (itemgetterobject * ig , PyObject * args , PyObject * kw )
1055
1064
{
1056
- PyObject * obj , * result ;
1057
- Py_ssize_t i , nitems = ig -> nitems ;
1058
-
1059
1065
assert (PyTuple_CheckExact (args ));
1060
1066
if (!_PyArg_NoKeywords ("itemgetter" , kw ))
1061
1067
return NULL ;
1062
1068
if (!_PyArg_CheckPositional ("itemgetter" , PyTuple_GET_SIZE (args ), 1 , 1 ))
1063
1069
return NULL ;
1070
+ return itemgetter_call_impl (ig , PyTuple_GET_ITEM (args , 0 ));
1071
+ }
1064
1072
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 ;
1066
1092
if (nitems == 1 ) {
1067
1093
if (ig -> index >= 0
1068
1094
&& PyTuple_CheckExact (obj )
@@ -1130,6 +1156,11 @@ static PyMethodDef itemgetter_methods[] = {
1130
1156
{NULL }
1131
1157
};
1132
1158
1159
+ static PyMemberDef itemgetter_members [] = {
1160
+ {"__vectorcalloffset__" , T_PYSSIZET , offsetof(itemgetterobject , vectorcall ), READONLY },
1161
+ {NULL } /* Sentinel */
1162
+ };
1163
+
1133
1164
PyDoc_STRVAR (itemgetter_doc ,
1134
1165
"itemgetter(item, ...) --> itemgetter object\n\
1135
1166
\n\
@@ -1144,6 +1175,7 @@ static PyType_Slot itemgetter_type_slots[] = {
1144
1175
{Py_tp_traverse , itemgetter_traverse },
1145
1176
{Py_tp_clear , itemgetter_clear },
1146
1177
{Py_tp_methods , itemgetter_methods },
1178
+ {Py_tp_members , itemgetter_members },
1147
1179
{Py_tp_new , itemgetter_new },
1148
1180
{Py_tp_getattro , PyObject_GenericGetAttr },
1149
1181
{Py_tp_repr , itemgetter_repr },
@@ -1155,7 +1187,7 @@ static PyType_Spec itemgetter_type_spec = {
1155
1187
.basicsize = sizeof (itemgetterobject ),
1156
1188
.itemsize = 0 ,
1157
1189
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1158
- Py_TPFLAGS_IMMUTABLETYPE ),
1190
+ Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_VECTORCALL ),
1159
1191
.slots = itemgetter_type_slots ,
1160
1192
};
1161
1193
@@ -1165,8 +1197,15 @@ typedef struct {
1165
1197
PyObject_HEAD
1166
1198
Py_ssize_t nattrs ;
1167
1199
PyObject * attr ;
1200
+ vectorcallfunc vectorcall ;
1168
1201
} attrgetterobject ;
1169
1202
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
+
1170
1209
/* AC 3.5: treats first argument as an iterable, otherwise uses *args */
1171
1210
static PyObject *
1172
1211
attrgetter_new (PyTypeObject * type , PyObject * args , PyObject * kwds )
@@ -1210,7 +1249,7 @@ attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1210
1249
kind = PyUnicode_KIND (item );
1211
1250
data = PyUnicode_DATA (item );
1212
1251
1213
- /* check whethere the string is dotted */
1252
+ /* check whether the string is dotted */
1214
1253
dot_count = 0 ;
1215
1254
for (char_idx = 0 ; char_idx < item_len ; ++ char_idx ) {
1216
1255
if (PyUnicode_READ (kind , data , char_idx ) == '.' )
@@ -1276,6 +1315,7 @@ attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1276
1315
1277
1316
ag -> attr = attr ;
1278
1317
ag -> nattrs = nattrs ;
1318
+ ag -> vectorcall = (vectorcallfunc )attrgetter_vectorcall ;
1279
1319
1280
1320
PyObject_GC_Track (ag );
1281
1321
return (PyObject * )ag ;
@@ -1342,16 +1382,36 @@ dotted_getattr(PyObject *obj, PyObject *attr)
1342
1382
static PyObject *
1343
1383
attrgetter_call (attrgetterobject * ag , PyObject * args , PyObject * kw )
1344
1384
{
1345
- PyObject * obj , * result ;
1346
- Py_ssize_t i , nattrs = ag -> nattrs ;
1347
-
1348
1385
if (!_PyArg_NoKeywords ("attrgetter" , kw ))
1349
1386
return NULL ;
1350
1387
if (!_PyArg_CheckPositional ("attrgetter" , PyTuple_GET_SIZE (args ), 1 , 1 ))
1351
1388
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 */
1354
1413
return dotted_getattr (obj , PyTuple_GET_ITEM (ag -> attr , 0 ));
1414
+ }
1355
1415
1356
1416
assert (PyTuple_Check (ag -> attr ));
1357
1417
assert (PyTuple_GET_SIZE (ag -> attr ) == nattrs );
@@ -1460,6 +1520,11 @@ static PyMethodDef attrgetter_methods[] = {
1460
1520
{NULL }
1461
1521
};
1462
1522
1523
+ static PyMemberDef attrgetter_members [] = {
1524
+ {"__vectorcalloffset__" , T_PYSSIZET , offsetof(attrgetterobject , vectorcall ), READONLY },
1525
+ {NULL } /* Sentinel*/
1526
+ };
1527
+
1463
1528
PyDoc_STRVAR (attrgetter_doc ,
1464
1529
"attrgetter(attr, ...) --> attrgetter object\n\
1465
1530
\n\
@@ -1476,6 +1541,7 @@ static PyType_Slot attrgetter_type_slots[] = {
1476
1541
{Py_tp_traverse , attrgetter_traverse },
1477
1542
{Py_tp_clear , attrgetter_clear },
1478
1543
{Py_tp_methods , attrgetter_methods },
1544
+ {Py_tp_members , attrgetter_members },
1479
1545
{Py_tp_new , attrgetter_new },
1480
1546
{Py_tp_getattro , PyObject_GenericGetAttr },
1481
1547
{Py_tp_repr , attrgetter_repr },
@@ -1487,7 +1553,7 @@ static PyType_Spec attrgetter_type_spec = {
1487
1553
.basicsize = sizeof (attrgetterobject ),
1488
1554
.itemsize = 0 ,
1489
1555
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1490
- Py_TPFLAGS_IMMUTABLETYPE ),
1556
+ Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_VECTORCALL ),
1491
1557
.slots = attrgetter_type_slots ,
1492
1558
};
1493
1559
0 commit comments