Skip to content

Commit 4033d27

Browse files
committed
Add vectorcall for attrgetter objects
1 parent f8e7d88 commit 4033d27

File tree

1 file changed

+41
-8
lines changed

1 file changed

+41
-8
lines changed

Modules/_operator.c

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,6 @@ Return a callable object that fetches the given item(s) from its operand.\n\
11471147
After f = itemgetter(2), the call f(r) returns r[2].\n\
11481148
After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])");
11491149

1150-
11511150
static PyType_Slot itemgetter_type_slots[] = {
11521151
{Py_tp_doc, (void *)itemgetter_doc},
11531152
{Py_tp_dealloc, itemgetter_dealloc},
@@ -1177,8 +1176,15 @@ typedef struct {
11771176
PyObject_HEAD
11781177
Py_ssize_t nattrs;
11791178
PyObject *attr;
1179+
vectorcallfunc vectorcall;
11801180
} attrgetterobject;
11811181

1182+
// Forward declarations
1183+
static PyObject *
1184+
attrgetter_vectorcall(PyObject *, PyObject *const *, size_t, PyObject *);
1185+
static PyObject *
1186+
attrgetter_call_impl(attrgetterobject *, PyObject *);
1187+
11821188
/* AC 3.5: treats first argument as an iterable, otherwise uses *args */
11831189
static PyObject *
11841190
attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
@@ -1222,7 +1228,7 @@ attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
12221228
kind = PyUnicode_KIND(item);
12231229
data = PyUnicode_DATA(item);
12241230

1225-
/* check whethere the string is dotted */
1231+
/* check whether the string is dotted */
12261232
dot_count = 0;
12271233
for (char_idx = 0; char_idx < item_len; ++char_idx) {
12281234
if (PyUnicode_READ(kind, data, char_idx) == '.')
@@ -1288,6 +1294,7 @@ attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
12881294

12891295
ag->attr = attr;
12901296
ag->nattrs = nattrs;
1297+
ag->vectorcall = (vectorcallfunc)attrgetter_vectorcall;
12911298

12921299
PyObject_GC_Track(ag);
12931300
return (PyObject *)ag;
@@ -1354,16 +1361,36 @@ dotted_getattr(PyObject *obj, PyObject *attr)
13541361
static PyObject *
13551362
attrgetter_call(attrgetterobject *ag, PyObject *args, PyObject *kw)
13561363
{
1357-
PyObject *obj, *result;
1358-
Py_ssize_t i, nattrs=ag->nattrs;
1359-
13601364
if (!_PyArg_NoKeywords("attrgetter", kw))
13611365
return NULL;
13621366
if (!_PyArg_CheckPositional("attrgetter", PyTuple_GET_SIZE(args), 1, 1))
13631367
return NULL;
1364-
obj = PyTuple_GET_ITEM(args, 0);
1365-
if (ag->nattrs == 1) /* ag->attr is always a tuple */
1368+
return attrgetter_call_impl(ag, PyTuple_GET_ITEM(args, 0));
1369+
}
1370+
1371+
static PyObject *
1372+
attrgetter_vectorcall(PyObject *ag, PyObject *const *args, size_t nargsf, PyObject *kwnames)
1373+
{
1374+
if (!_PyArg_NoKwnames("attrgetter", kwnames)) {
1375+
return NULL;
1376+
}
1377+
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
1378+
if (!_PyArg_CheckPositional("attrgetter", nargs, 1, 1)) {
1379+
return NULL;
1380+
}
1381+
return attrgetter_call_impl((attrgetterobject *)ag, args[0]);
1382+
}
1383+
1384+
static PyObject *
1385+
attrgetter_call_impl(attrgetterobject *ag, PyObject *obj)
1386+
{
1387+
PyObject *result;
1388+
Py_ssize_t i, nattrs=ag->nattrs;
1389+
1390+
if (ag->nattrs == 1) {
1391+
/* ag->attr is always a tuple */
13661392
return dotted_getattr(obj, PyTuple_GET_ITEM(ag->attr, 0));
1393+
}
13671394

13681395
assert(PyTuple_Check(ag->attr));
13691396
assert(PyTuple_GET_SIZE(ag->attr) == nattrs);
@@ -1472,6 +1499,11 @@ static PyMethodDef attrgetter_methods[] = {
14721499
{NULL}
14731500
};
14741501

1502+
static PyMemberDef attrgetter_members[] = {
1503+
{"__vectorcalloffset__", T_PYSSIZET, offsetof(attrgetterobject, vectorcall), READONLY},
1504+
{NULL} /* Sentinel*/
1505+
};
1506+
14751507
PyDoc_STRVAR(attrgetter_doc,
14761508
"attrgetter(attr, ...) --> attrgetter object\n\
14771509
\n\
@@ -1488,6 +1520,7 @@ static PyType_Slot attrgetter_type_slots[] = {
14881520
{Py_tp_traverse, attrgetter_traverse},
14891521
{Py_tp_clear, attrgetter_clear},
14901522
{Py_tp_methods, attrgetter_methods},
1523+
{Py_tp_members, attrgetter_members},
14911524
{Py_tp_new, attrgetter_new},
14921525
{Py_tp_getattro, PyObject_GenericGetAttr},
14931526
{Py_tp_repr, attrgetter_repr},
@@ -1499,7 +1532,7 @@ static PyType_Spec attrgetter_type_spec = {
14991532
.basicsize = sizeof(attrgetterobject),
15001533
.itemsize = 0,
15011534
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
1502-
Py_TPFLAGS_IMMUTABLETYPE),
1535+
Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_HAVE_VECTORCALL),
15031536
.slots = attrgetter_type_slots,
15041537
};
15051538

0 commit comments

Comments
 (0)