Skip to content

Commit 8476e31

Browse files
itamarofacebook-github-bot
authored andcommitted
Backport gh-90350: Optimize builtin functions min() and max() (GH-30286)
Summary: Builtin functions min() and max() now use METH_FASTCALL upstream issue: python/cpython#90350 upstream PR: python/cpython#30286 upstream commit: python/cpython@0066ab5 Reviewed By: carljm Differential Revision: D52650071 fbshipit-source-id: 93971e865ab9515efc9771c58582f63d15e0342d
1 parent 07eaad1 commit 8476e31

File tree

2 files changed

+54
-36
lines changed

2 files changed

+54
-36
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Optimize builtin functions :func:`min` and :func:`max`.

Python/bltinmodule.c

+53-36
Original file line numberDiff line numberDiff line change
@@ -1747,45 +1747,47 @@ builtin_locals_impl(PyObject *module)
17471747

17481748

17491749
static PyObject *
1750-
min_max(PyObject *args, PyObject *kwds, int op)
1750+
min_max(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames, int op)
17511751
{
1752-
PyObject *v, *it, *item, *val, *maxitem, *maxval, *keyfunc=NULL;
1753-
PyObject *emptytuple, *defaultval = NULL;
1754-
static char *kwlist[] = {"key", "default", NULL};
1755-
const char *name = op == Py_LT ? "min" : "max";
1756-
const int positional = PyTuple_Size(args) > 1;
1757-
int ret;
1752+
PyObject *it = NULL, *item, *val, *maxitem, *maxval, *keyfunc=NULL;
1753+
PyObject *defaultval = NULL;
1754+
static const char * const keywords[] = {"key", "default", NULL};
1755+
static _PyArg_Parser _parser_min = {
1756+
.format = "|$OO:min",
1757+
.keywords = keywords,
1758+
.fname = 0,
1759+
};
1760+
static _PyArg_Parser _parser_max = {
1761+
.format = "|$OO:max",
1762+
.keywords = keywords,
1763+
.fname = 0,
1764+
};
1765+
const char *name = (op == Py_LT) ? "min" : "max";
1766+
_PyArg_Parser *_parser = (op == Py_LT) ? &_parser_min : &_parser_max;
17581767

1759-
if (positional) {
1760-
v = args;
1761-
}
1762-
else if (!PyArg_UnpackTuple(args, name, 1, 1, &v)) {
1763-
if (PyExceptionClass_Check(PyExc_TypeError)) {
1764-
PyErr_Format(PyExc_TypeError, "%s expected at least 1 argument, got 0", name);
1765-
}
1768+
if (nargs == 0) {
1769+
PyErr_Format(PyExc_TypeError, "%s expected at least 1 argument, got 0", name);
17661770
return NULL;
17671771
}
17681772

1769-
emptytuple = PyTuple_New(0);
1770-
if (emptytuple == NULL)
1771-
return NULL;
1772-
ret = PyArg_ParseTupleAndKeywords(emptytuple, kwds,
1773-
(op == Py_LT) ? "|$OO:min" : "|$OO:max",
1774-
kwlist, &keyfunc, &defaultval);
1775-
Py_DECREF(emptytuple);
1776-
if (!ret)
1773+
if (kwnames != NULL && !_PyArg_ParseStackAndKeywords(args + nargs, 0, kwnames, _parser,
1774+
&keyfunc, &defaultval)) {
17771775
return NULL;
1776+
}
17781777

1778+
const int positional = nargs > 1; // False iff nargs == 1
17791779
if (positional && defaultval != NULL) {
17801780
PyErr_Format(PyExc_TypeError,
17811781
"Cannot specify a default for %s() with multiple "
17821782
"positional arguments", name);
17831783
return NULL;
17841784
}
17851785

1786-
it = PyObject_GetIter(v);
1787-
if (it == NULL) {
1788-
return NULL;
1786+
if (!positional) {
1787+
it = PyObject_GetIter(args[0]);
1788+
if (it == NULL) {
1789+
return NULL;
1790+
}
17891791
}
17901792

17911793
if (keyfunc == Py_None) {
@@ -1794,7 +1796,24 @@ min_max(PyObject *args, PyObject *kwds, int op)
17941796

17951797
maxitem = NULL; /* the result */
17961798
maxval = NULL; /* the value associated with the result */
1797-
while (( item = PyIter_Next(it) )) {
1799+
while (1) {
1800+
if (it == NULL) {
1801+
if (nargs-- <= 0) {
1802+
break;
1803+
}
1804+
item = *args++;
1805+
Py_INCREF(item);
1806+
}
1807+
else {
1808+
item = PyIter_Next(it);
1809+
if (item == NULL) {
1810+
if (PyErr_Occurred()) {
1811+
goto Fail_it;
1812+
}
1813+
break;
1814+
}
1815+
}
1816+
17981817
/* get the value from the key function */
17991818
if (keyfunc != NULL) {
18001819
val = PyObject_CallOneArg(keyfunc, item);
@@ -1828,8 +1847,6 @@ min_max(PyObject *args, PyObject *kwds, int op)
18281847
}
18291848
}
18301849
}
1831-
if (PyErr_Occurred())
1832-
goto Fail_it;
18331850
if (maxval == NULL) {
18341851
assert(maxitem == NULL);
18351852
if (defaultval != NULL) {
@@ -1841,7 +1858,7 @@ min_max(PyObject *args, PyObject *kwds, int op)
18411858
}
18421859
else
18431860
Py_DECREF(maxval);
1844-
Py_DECREF(it);
1861+
Py_XDECREF(it);
18451862
return maxitem;
18461863

18471864
Fail_it_item_and_val:
@@ -1851,15 +1868,15 @@ min_max(PyObject *args, PyObject *kwds, int op)
18511868
Fail_it:
18521869
Py_XDECREF(maxval);
18531870
Py_XDECREF(maxitem);
1854-
Py_DECREF(it);
1871+
Py_XDECREF(it);
18551872
return NULL;
18561873
}
18571874

18581875
/* AC: cannot convert yet, waiting for *args support */
18591876
static PyObject *
1860-
builtin_min(PyObject *self, PyObject *args, PyObject *kwds)
1877+
builtin_min(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
18611878
{
1862-
return min_max(args, kwds, Py_LT);
1879+
return min_max(args, nargs, kwnames, Py_LT);
18631880
}
18641881

18651882
PyDoc_STRVAR(min_doc,
@@ -1874,9 +1891,9 @@ With two or more arguments, return the smallest argument.");
18741891

18751892
/* AC: cannot convert yet, waiting for *args support */
18761893
static PyObject *
1877-
builtin_max(PyObject *self, PyObject *args, PyObject *kwds)
1894+
builtin_max(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
18781895
{
1879-
return min_max(args, kwds, Py_GT);
1896+
return min_max(args, nargs, kwnames, Py_GT);
18801897
}
18811898

18821899
PyDoc_STRVAR(max_doc,
@@ -3042,8 +3059,8 @@ static PyMethodDef builtin_methods[] = {
30423059
BUILTIN_AITER_METHODDEF
30433060
BUILTIN_LEN_METHODDEF
30443061
BUILTIN_LOCALS_METHODDEF
3045-
{"max", _PyCFunction_CAST(builtin_max), METH_VARARGS | METH_KEYWORDS, max_doc},
3046-
{"min", _PyCFunction_CAST(builtin_min), METH_VARARGS | METH_KEYWORDS, min_doc},
3062+
{"max", _PyCFunction_CAST(builtin_max), METH_FASTCALL | METH_KEYWORDS, max_doc},
3063+
{"min", _PyCFunction_CAST(builtin_min), METH_FASTCALL | METH_KEYWORDS, min_doc},
30473064
BUILTIN_NEXT_METHODDEF
30483065
BUILTIN_ANEXT_METHODDEF
30493066
BUILTIN_OCT_METHODDEF

0 commit comments

Comments
 (0)