Skip to content

Commit a9413ab

Browse files
committed
Builtin functions min() and max() now use METH_FASTCALL
1 parent 196b53e commit a9413ab

File tree

1 file changed

+39
-34
lines changed

1 file changed

+39
-34
lines changed

Python/bltinmodule.c

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,45 +1705,39 @@ builtin_locals_impl(PyObject *module)
17051705

17061706

17071707
static PyObject *
1708-
min_max(PyObject *args, PyObject *kwds, int op)
1708+
min_max(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames, int op)
17091709
{
1710-
PyObject *v, *it, *item, *val, *maxitem, *maxval, *keyfunc=NULL;
1711-
PyObject *emptytuple, *defaultval = NULL;
1712-
static char *kwlist[] = {"key", "default", NULL};
1713-
const char *name = op == Py_LT ? "min" : "max";
1714-
const int positional = PyTuple_Size(args) > 1;
1715-
int ret;
1710+
PyObject *it, *item, *val, *maxitem, *maxval, *keyfunc=NULL;
1711+
PyObject *defaultval = NULL;
1712+
static const char * const keywords[] = {"key", "default", NULL};
1713+
static _PyArg_Parser _parser_min = {"|$OO:min", keywords, 0};
1714+
static _PyArg_Parser _parser_max = {"|$OO:max", keywords, 0};
1715+
const char *name = (op == Py_LT) ? "min" : "max";
1716+
_PyArg_Parser *_parser = (op == Py_LT) ? &_parser_min : &_parser_max;
17161717

1717-
if (positional) {
1718-
v = args;
1719-
}
1720-
else if (!PyArg_UnpackTuple(args, name, 1, 1, &v)) {
1721-
if (PyExceptionClass_Check(PyExc_TypeError)) {
1722-
PyErr_Format(PyExc_TypeError, "%s expected at least 1 argument, got 0", name);
1723-
}
1718+
if (nargs == 0) {
1719+
PyErr_Format(PyExc_TypeError, "%s expected at least 1 argument, got 0", name);
17241720
return NULL;
17251721
}
17261722

1727-
emptytuple = PyTuple_New(0);
1728-
if (emptytuple == NULL)
1729-
return NULL;
1730-
ret = PyArg_ParseTupleAndKeywords(emptytuple, kwds,
1731-
(op == Py_LT) ? "|$OO:min" : "|$OO:max",
1732-
kwlist, &keyfunc, &defaultval);
1733-
Py_DECREF(emptytuple);
1734-
if (!ret)
1723+
if (kwnames != NULL && !_PyArg_ParseStackAndKeywords(args + nargs, 0, kwnames, _parser,
1724+
&keyfunc, &defaultval)) {
17351725
return NULL;
1726+
}
17361727

1728+
const int positional = nargs > 1; // False iff nargs == 1
17371729
if (positional && defaultval != NULL) {
17381730
PyErr_Format(PyExc_TypeError,
17391731
"Cannot specify a default for %s() with multiple "
17401732
"positional arguments", name);
17411733
return NULL;
17421734
}
17431735

1744-
it = PyObject_GetIter(v);
1745-
if (it == NULL) {
1746-
return NULL;
1736+
if (!positional) {
1737+
it = PyObject_GetIter(args[0]);
1738+
if (it == NULL) {
1739+
return NULL;
1740+
}
17471741
}
17481742

17491743
if (keyfunc == Py_None) {
@@ -1752,7 +1746,14 @@ min_max(PyObject *args, PyObject *kwds, int op)
17521746

17531747
maxitem = NULL; /* the result */
17541748
maxval = NULL; /* the value associated with the result */
1755-
while (( item = PyIter_Next(it) )) {
1749+
int i = 0;
1750+
while (positional ?
1751+
((i < nargs) && (item = args[i++]))
1752+
: !!(item = PyIter_Next(it))) {
1753+
if (positional) {
1754+
Py_INCREF(item);
1755+
}
1756+
17561757
/* get the value from the key function */
17571758
if (keyfunc != NULL) {
17581759
val = PyObject_CallOneArg(keyfunc, item);
@@ -1801,7 +1802,9 @@ min_max(PyObject *args, PyObject *kwds, int op)
18011802
}
18021803
else
18031804
Py_DECREF(maxval);
1804-
Py_DECREF(it);
1805+
if (!positional) {
1806+
Py_DECREF(it);
1807+
}
18051808
return maxitem;
18061809

18071810
Fail_it_item_and_val:
@@ -1811,15 +1814,17 @@ min_max(PyObject *args, PyObject *kwds, int op)
18111814
Fail_it:
18121815
Py_XDECREF(maxval);
18131816
Py_XDECREF(maxitem);
1814-
Py_DECREF(it);
1817+
if (!positional) {
1818+
Py_DECREF(it);
1819+
}
18151820
return NULL;
18161821
}
18171822

18181823
/* AC: cannot convert yet, waiting for *args support */
18191824
static PyObject *
1820-
builtin_min(PyObject *self, PyObject *args, PyObject *kwds)
1825+
builtin_min(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
18211826
{
1822-
return min_max(args, kwds, Py_LT);
1827+
return min_max(args, nargs, kwnames, Py_LT);
18231828
}
18241829

18251830
PyDoc_STRVAR(min_doc,
@@ -1834,9 +1839,9 @@ With two or more arguments, return the smallest argument.");
18341839

18351840
/* AC: cannot convert yet, waiting for *args support */
18361841
static PyObject *
1837-
builtin_max(PyObject *self, PyObject *args, PyObject *kwds)
1842+
builtin_max(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
18381843
{
1839-
return min_max(args, kwds, Py_GT);
1844+
return min_max(args, nargs, kwnames, Py_GT);
18401845
}
18411846

18421847
PyDoc_STRVAR(max_doc,
@@ -2954,8 +2959,8 @@ static PyMethodDef builtin_methods[] = {
29542959
BUILTIN_AITER_METHODDEF
29552960
BUILTIN_LEN_METHODDEF
29562961
BUILTIN_LOCALS_METHODDEF
2957-
{"max", (PyCFunction)(void(*)(void))builtin_max, METH_VARARGS | METH_KEYWORDS, max_doc},
2958-
{"min", (PyCFunction)(void(*)(void))builtin_min, METH_VARARGS | METH_KEYWORDS, min_doc},
2962+
{"max", (PyCFunction)(void(*)(void))builtin_max, METH_FASTCALL | METH_KEYWORDS, max_doc},
2963+
{"min", (PyCFunction)(void(*)(void))builtin_min, METH_FASTCALL | METH_KEYWORDS, min_doc},
29592964
{"next", (PyCFunction)(void(*)(void))builtin_next, METH_FASTCALL, next_doc},
29602965
BUILTIN_ANEXT_METHODDEF
29612966
BUILTIN_OCT_METHODDEF

0 commit comments

Comments
 (0)