-
-
Notifications
You must be signed in to change notification settings - Fork 32.1k
bpo-37207: Use vectorcall for range() #18464
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
b4f3271
6d8063b
804e18c
663d8cc
b4559ce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
|
||
#include "Python.h" | ||
#include "structmember.h" | ||
#include "pycore_tupleobject.h" | ||
|
||
/* Support objects whose length is > PY_SSIZE_T_MAX. | ||
|
||
|
@@ -71,43 +72,35 @@ 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, size_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); | ||
return NULL; | ||
} | ||
break; | ||
case 1: | ||
stop = PyTuple_GET_ITEM(args, 0); | ||
stop = PyNumber_Index(stop); | ||
stop = PyNumber_Index(args[0]); | ||
if (!stop) { | ||
return NULL; | ||
} | ||
|
@@ -122,14 +115,14 @@ range_new(PyTypeObject *type, PyObject *args, PyObject *kw) | |
return NULL; | ||
default: | ||
PyErr_Format(PyExc_TypeError, | ||
"range expected at most 3 arguments, got %zd", | ||
"range expected at most 3 arguments, got %zu", | ||
num_args); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It should be reset to %zd, since num_args is signed, no? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right. |
||
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,64 +131,26 @@ 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) | ||
{ | ||
rangeobject *obj; | ||
size_t nargs = PyVectorcall_NARGS(nargsf); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I didn't expect a size_t here. I opened an issue to discuss PyVectorcall_NARGS() return type: https://bugs.python.org/issue39611 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The return type already is Py_ssize_t. The bug was only in this patch. |
||
PyObject *start = NULL, *stop = NULL, *step = NULL; | ||
if (kwnames && PyTuple_GET_SIZE(kwnames) != 0) { | ||
PyErr_Format(PyExc_TypeError, "range() takes no keyword arguments"); | ||
return NULL; | ||
} | ||
switch(nargs) { | ||
case 0: | ||
PyErr_Format(PyExc_TypeError, "range() expected 1 arguments, got 0"); | ||
return NULL; | ||
case 1: | ||
stop = PyNumber_Index(args[0]); | ||
if (!stop) | ||
return NULL; | ||
Py_INCREF(_PyLong_Zero); | ||
start = _PyLong_Zero; | ||
Py_INCREF(_PyLong_One); | ||
step = _PyLong_One; | ||
break; | ||
case 3: | ||
step = args[2]; | ||
//Intentional fall through | ||
case 2: | ||
/* Convert borrowed refs to owned refs */ | ||
start = PyNumber_Index(args[0]); | ||
if (!start) | ||
return NULL; | ||
stop = PyNumber_Index(args[1]); | ||
if (!stop) { | ||
Py_DECREF(start); | ||
return NULL; | ||
} | ||
step = validate_step(step); /* Caution, this can clear exceptions */ | ||
if (!step) { | ||
Py_DECREF(start); | ||
Py_DECREF(stop); | ||
return NULL; | ||
} | ||
break; | ||
default: | ||
PyErr_Format(PyExc_TypeError, "range() expected at most 3 arguments, got %zu", nargs); | ||
return NULL; | ||
} | ||
obj = make_range_object(type, start, stop, step); | ||
if (obj != NULL) | ||
return (PyObject *) obj; | ||
|
||
/* Failed to create object, release attributes */ | ||
Py_DECREF(start); | ||
Py_DECREF(stop); | ||
Py_DECREF(step); | ||
return NULL; | ||
return range_from_array(type, args, nargs); | ||
} | ||
|
||
PyDoc_STRVAR(range_doc, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to use Py_ssize_t type for num_args. Usually, it's called "nargs", but I'm fine with "num_args" ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right,
Py_ssize_t
is more consistent.But I find
num_args
more descriptive, so I'll keep that name.