diff options
author | Petr Viktorin <encukou@gmail.com> | 2020-02-18 15:13:17 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-18 15:13:17 (GMT) |
commit | 6e35da976370e7c2e028165c65d7d7d42772a71f (patch) | |
tree | d589a75b9f8f2d1f1bf73947feb57a6b83cffebb /Objects | |
parent | 24bba8cf5b8db25c19bcd1d94e8e356874d1c723 (diff) | |
download | cpython-6e35da976370e7c2e028165c65d7d7d42772a71f.zip cpython-6e35da976370e7c2e028165c65d7d7d42772a71f.tar.gz cpython-6e35da976370e7c2e028165c65d7d7d42772a71f.tar.bz2 |
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
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/rangeobject.c | 50 |
1 files changed, 33 insertions, 17 deletions
diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 343a80c..123ca0b 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -2,6 +2,7 @@ #include "Python.h" #include "structmember.h" +#include "pycore_tupleobject.h" /* Support objects whose length is > PY_SSIZE_T_MAX. @@ -71,34 +72,27 @@ make_range_object(PyTypeObject *type, PyObject *start, range(0, 5, -1) */ 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; 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) { case 3: - step = PyTuple_GET_ITEM(args, 2); + step = args[2]; /* fallthrough */ case 2: - start = PyTuple_GET_ITEM(args, 0); - start = PyNumber_Index(start); + /* Convert borrowed refs to owned refs */ + start = PyNumber_Index(args[0]); if (!start) { return NULL; } - - stop = PyTuple_GET_ITEM(args, 1); - stop = PyNumber_Index(stop); + stop = PyNumber_Index(args[1]); if (!stop) { Py_DECREF(start); return NULL; } - - step = validate_step(step); + step = validate_step(step); /* Caution, this can clear exceptions */ if (!step) { Py_DECREF(start); Py_DECREF(stop); @@ -106,8 +100,7 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw) } break; case 1: - stop = PyTuple_GET_ITEM(args, 0); - stop = PyNumber_Index(stop); + stop = PyNumber_Index(args[0]); if (!stop) { return NULL; } @@ -126,10 +119,10 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw) num_args); return NULL; } - obj = make_range_object(type, start, stop, step); - if (obj != NULL) + if (obj != NULL) { return (PyObject *) obj; + } /* Failed to create object, release attributes */ Py_DECREF(start); @@ -138,6 +131,28 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw) 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, "range(stop) -> range object\n\ range(start, stop[, step]) -> range object\n\ @@ -719,6 +734,7 @@ PyTypeObject PyRange_Type = { 0, /* tp_init */ 0, /* tp_alloc */ range_new, /* tp_new */ + .tp_vectorcall = (vectorcallfunc)range_vectorcall }; /*********************** range Iterator **************************/ |