mirror of https://github.com/python/cpython
bpo-37207: Use vectorcall for range() (GH-18464)
This continues the `range()` part of #13930. The complete pull request is stalled on discussions around dicts, but `range()` should not be controversial. (And I plan to open PRs for other parts if this is merged.) On top of Mark's change, I unified `range_new` and `range_vectorcall`, which had a lot of duplicate code. https://bugs.python.org/issue37207
This commit is contained in:
parent
24bba8cf5b
commit
6e35da9763
|
@ -0,0 +1,2 @@
|
||||||
|
Speed up calls to ``range()`` by about 30%, by using the
|
||||||
|
PEP 590 ``vectorcall`` calling convention. Patch by Mark Shannon.
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include "structmember.h"
|
#include "structmember.h"
|
||||||
|
#include "pycore_tupleobject.h"
|
||||||
|
|
||||||
/* Support objects whose length is > PY_SSIZE_T_MAX.
|
/* Support objects whose length is > PY_SSIZE_T_MAX.
|
||||||
|
|
||||||
|
@ -71,34 +72,27 @@ make_range_object(PyTypeObject *type, PyObject *start,
|
||||||
range(0, 5, -1)
|
range(0, 5, -1)
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
range_from_array(PyTypeObject *type, PyObject *const *args, Py_ssize_t num_args)
|
||||||
{
|
{
|
||||||
rangeobject *obj;
|
rangeobject *obj;
|
||||||
PyObject *start = NULL, *stop = NULL, *step = NULL;
|
PyObject *start = NULL, *stop = NULL, *step = NULL;
|
||||||
|
|
||||||
if (!_PyArg_NoKeywords("range", kw))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
Py_ssize_t num_args = PyTuple_GET_SIZE(args);
|
|
||||||
switch (num_args) {
|
switch (num_args) {
|
||||||
case 3:
|
case 3:
|
||||||
step = PyTuple_GET_ITEM(args, 2);
|
step = args[2];
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
case 2:
|
case 2:
|
||||||
start = PyTuple_GET_ITEM(args, 0);
|
/* Convert borrowed refs to owned refs */
|
||||||
start = PyNumber_Index(start);
|
start = PyNumber_Index(args[0]);
|
||||||
if (!start) {
|
if (!start) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
stop = PyNumber_Index(args[1]);
|
||||||
stop = PyTuple_GET_ITEM(args, 1);
|
|
||||||
stop = PyNumber_Index(stop);
|
|
||||||
if (!stop) {
|
if (!stop) {
|
||||||
Py_DECREF(start);
|
Py_DECREF(start);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
step = validate_step(step); /* Caution, this can clear exceptions */
|
||||||
step = validate_step(step);
|
|
||||||
if (!step) {
|
if (!step) {
|
||||||
Py_DECREF(start);
|
Py_DECREF(start);
|
||||||
Py_DECREF(stop);
|
Py_DECREF(stop);
|
||||||
|
@ -106,8 +100,7 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
stop = PyTuple_GET_ITEM(args, 0);
|
stop = PyNumber_Index(args[0]);
|
||||||
stop = PyNumber_Index(stop);
|
|
||||||
if (!stop) {
|
if (!stop) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -126,10 +119,10 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
num_args);
|
num_args);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = make_range_object(type, start, stop, step);
|
obj = make_range_object(type, start, stop, step);
|
||||||
if (obj != NULL)
|
if (obj != NULL) {
|
||||||
return (PyObject *) obj;
|
return (PyObject *) obj;
|
||||||
|
}
|
||||||
|
|
||||||
/* Failed to create object, release attributes */
|
/* Failed to create object, release attributes */
|
||||||
Py_DECREF(start);
|
Py_DECREF(start);
|
||||||
|
@ -138,6 +131,28 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
|
{
|
||||||
|
if (!_PyArg_NoKeywords("range", kw))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return range_from_array(type, _PyTuple_ITEMS(args), PyTuple_GET_SIZE(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
range_vectorcall(PyTypeObject *type, PyObject *const *args,
|
||||||
|
size_t nargsf, PyObject *kwnames)
|
||||||
|
{
|
||||||
|
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
|
||||||
|
if (kwnames && PyTuple_GET_SIZE(kwnames) != 0) {
|
||||||
|
PyErr_Format(PyExc_TypeError, "range() takes no keyword arguments");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return range_from_array(type, args, nargs);
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(range_doc,
|
PyDoc_STRVAR(range_doc,
|
||||||
"range(stop) -> range object\n\
|
"range(stop) -> range object\n\
|
||||||
range(start, stop[, step]) -> range object\n\
|
range(start, stop[, step]) -> range object\n\
|
||||||
|
@ -719,6 +734,7 @@ PyTypeObject PyRange_Type = {
|
||||||
0, /* tp_init */
|
0, /* tp_init */
|
||||||
0, /* tp_alloc */
|
0, /* tp_alloc */
|
||||||
range_new, /* tp_new */
|
range_new, /* tp_new */
|
||||||
|
.tp_vectorcall = (vectorcallfunc)range_vectorcall
|
||||||
};
|
};
|
||||||
|
|
||||||
/*********************** range Iterator **************************/
|
/*********************** range Iterator **************************/
|
||||||
|
|
Loading…
Reference in New Issue