mirror of
https://github.com/python/cpython
synced 2024-09-15 22:58:09 +00:00
gh-90350: Optimize builtin functions min() and max() (GH-30286)
Builtin functions min() and max() now use METH_FASTCALL
This commit is contained in:
parent
d70e27f258
commit
0066ab5bc5
|
@ -0,0 +1 @@
|
||||||
|
Optimize builtin functions :func:`min` and :func:`max`.
|
|
@ -1766,35 +1766,27 @@ builtin_locals_impl(PyObject *module)
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
min_max(PyObject *args, PyObject *kwds, int op)
|
min_max(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames, int op)
|
||||||
{
|
{
|
||||||
PyObject *v, *it, *item, *val, *maxitem, *maxval, *keyfunc=NULL;
|
PyObject *it = NULL, *item, *val, *maxitem, *maxval, *keyfunc=NULL;
|
||||||
PyObject *emptytuple, *defaultval = NULL;
|
PyObject *defaultval = NULL;
|
||||||
static char *kwlist[] = {"key", "default", NULL};
|
static const char * const keywords[] = {"key", "default", NULL};
|
||||||
const char *name = op == Py_LT ? "min" : "max";
|
static _PyArg_Parser _parser_min = {"|$OO:min", keywords, 0};
|
||||||
const int positional = PyTuple_Size(args) > 1;
|
static _PyArg_Parser _parser_max = {"|$OO:max", keywords, 0};
|
||||||
int ret;
|
const char *name = (op == Py_LT) ? "min" : "max";
|
||||||
|
_PyArg_Parser *_parser = (op == Py_LT) ? &_parser_min : &_parser_max;
|
||||||
|
|
||||||
if (positional) {
|
if (nargs == 0) {
|
||||||
v = args;
|
|
||||||
}
|
|
||||||
else if (!PyArg_UnpackTuple(args, name, 1, 1, &v)) {
|
|
||||||
if (PyExceptionClass_Check(PyExc_TypeError)) {
|
|
||||||
PyErr_Format(PyExc_TypeError, "%s expected at least 1 argument, got 0", name);
|
PyErr_Format(PyExc_TypeError, "%s expected at least 1 argument, got 0", name);
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
emptytuple = PyTuple_New(0);
|
if (kwnames != NULL && !_PyArg_ParseStackAndKeywords(args + nargs, 0, kwnames, _parser,
|
||||||
if (emptytuple == NULL)
|
&keyfunc, &defaultval)) {
|
||||||
return NULL;
|
|
||||||
ret = PyArg_ParseTupleAndKeywords(emptytuple, kwds,
|
|
||||||
(op == Py_LT) ? "|$OO:min" : "|$OO:max",
|
|
||||||
kwlist, &keyfunc, &defaultval);
|
|
||||||
Py_DECREF(emptytuple);
|
|
||||||
if (!ret)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int positional = nargs > 1; // False iff nargs == 1
|
||||||
if (positional && defaultval != NULL) {
|
if (positional && defaultval != NULL) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"Cannot specify a default for %s() with multiple "
|
"Cannot specify a default for %s() with multiple "
|
||||||
|
@ -1802,10 +1794,12 @@ min_max(PyObject *args, PyObject *kwds, int op)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
it = PyObject_GetIter(v);
|
if (!positional) {
|
||||||
|
it = PyObject_GetIter(args[0]);
|
||||||
if (it == NULL) {
|
if (it == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (keyfunc == Py_None) {
|
if (keyfunc == Py_None) {
|
||||||
keyfunc = NULL;
|
keyfunc = NULL;
|
||||||
|
@ -1813,7 +1807,24 @@ min_max(PyObject *args, PyObject *kwds, int op)
|
||||||
|
|
||||||
maxitem = NULL; /* the result */
|
maxitem = NULL; /* the result */
|
||||||
maxval = NULL; /* the value associated with the result */
|
maxval = NULL; /* the value associated with the result */
|
||||||
while (( item = PyIter_Next(it) )) {
|
while (1) {
|
||||||
|
if (it == NULL) {
|
||||||
|
if (nargs-- <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
item = *args++;
|
||||||
|
Py_INCREF(item);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item = PyIter_Next(it);
|
||||||
|
if (item == NULL) {
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
goto Fail_it;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* get the value from the key function */
|
/* get the value from the key function */
|
||||||
if (keyfunc != NULL) {
|
if (keyfunc != NULL) {
|
||||||
val = PyObject_CallOneArg(keyfunc, item);
|
val = PyObject_CallOneArg(keyfunc, item);
|
||||||
|
@ -1847,8 +1858,6 @@ min_max(PyObject *args, PyObject *kwds, int op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (PyErr_Occurred())
|
|
||||||
goto Fail_it;
|
|
||||||
if (maxval == NULL) {
|
if (maxval == NULL) {
|
||||||
assert(maxitem == NULL);
|
assert(maxitem == NULL);
|
||||||
if (defaultval != NULL) {
|
if (defaultval != NULL) {
|
||||||
|
@ -1860,7 +1869,7 @@ min_max(PyObject *args, PyObject *kwds, int op)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Py_DECREF(maxval);
|
Py_DECREF(maxval);
|
||||||
Py_DECREF(it);
|
Py_XDECREF(it);
|
||||||
return maxitem;
|
return maxitem;
|
||||||
|
|
||||||
Fail_it_item_and_val:
|
Fail_it_item_and_val:
|
||||||
|
@ -1870,15 +1879,15 @@ min_max(PyObject *args, PyObject *kwds, int op)
|
||||||
Fail_it:
|
Fail_it:
|
||||||
Py_XDECREF(maxval);
|
Py_XDECREF(maxval);
|
||||||
Py_XDECREF(maxitem);
|
Py_XDECREF(maxitem);
|
||||||
Py_DECREF(it);
|
Py_XDECREF(it);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* AC: cannot convert yet, waiting for *args support */
|
/* AC: cannot convert yet, waiting for *args support */
|
||||||
static PyObject *
|
static PyObject *
|
||||||
builtin_min(PyObject *self, PyObject *args, PyObject *kwds)
|
builtin_min(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
{
|
{
|
||||||
return min_max(args, kwds, Py_LT);
|
return min_max(args, nargs, kwnames, Py_LT);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(min_doc,
|
PyDoc_STRVAR(min_doc,
|
||||||
|
@ -1893,9 +1902,9 @@ With two or more positional arguments, return the smallest argument.");
|
||||||
|
|
||||||
/* AC: cannot convert yet, waiting for *args support */
|
/* AC: cannot convert yet, waiting for *args support */
|
||||||
static PyObject *
|
static PyObject *
|
||||||
builtin_max(PyObject *self, PyObject *args, PyObject *kwds)
|
builtin_max(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
{
|
{
|
||||||
return min_max(args, kwds, Py_GT);
|
return min_max(args, nargs, kwnames, Py_GT);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(max_doc,
|
PyDoc_STRVAR(max_doc,
|
||||||
|
@ -3054,8 +3063,8 @@ static PyMethodDef builtin_methods[] = {
|
||||||
BUILTIN_AITER_METHODDEF
|
BUILTIN_AITER_METHODDEF
|
||||||
BUILTIN_LEN_METHODDEF
|
BUILTIN_LEN_METHODDEF
|
||||||
BUILTIN_LOCALS_METHODDEF
|
BUILTIN_LOCALS_METHODDEF
|
||||||
{"max", _PyCFunction_CAST(builtin_max), METH_VARARGS | METH_KEYWORDS, max_doc},
|
{"max", _PyCFunction_CAST(builtin_max), METH_FASTCALL | METH_KEYWORDS, max_doc},
|
||||||
{"min", _PyCFunction_CAST(builtin_min), METH_VARARGS | METH_KEYWORDS, min_doc},
|
{"min", _PyCFunction_CAST(builtin_min), METH_FASTCALL | METH_KEYWORDS, min_doc},
|
||||||
{"next", _PyCFunction_CAST(builtin_next), METH_FASTCALL, next_doc},
|
{"next", _PyCFunction_CAST(builtin_next), METH_FASTCALL, next_doc},
|
||||||
BUILTIN_ANEXT_METHODDEF
|
BUILTIN_ANEXT_METHODDEF
|
||||||
BUILTIN_OCT_METHODDEF
|
BUILTIN_OCT_METHODDEF
|
||||||
|
|
Loading…
Reference in a new issue