summaryrefslogtreecommitdiffstats
path: root/Objects/listobject.c
diff options
context:
space:
mode:
authorRaymond Hettinger <rhettinger@users.noreply.github.com>2018-10-11 03:37:28 (GMT)
committerGitHub <noreply@github.com>2018-10-11 03:37:28 (GMT)
commitf1aa8aed4a8ce9753ffa8713e7d3461663e0624d (patch)
tree8ffff1e5e92b83b48b4d072acc4136a72977af3f /Objects/listobject.c
parent1d26c72e6a9c5b28b27c158f2f196217707dbb0f (diff)
downloadcpython-f1aa8aed4a8ce9753ffa8713e7d3461663e0624d.zip
cpython-f1aa8aed4a8ce9753ffa8713e7d3461663e0624d.tar.gz
cpython-f1aa8aed4a8ce9753ffa8713e7d3461663e0624d.tar.bz2
Micro-optimize list index range checks (GH-9784)
Diffstat (limited to 'Objects/listobject.c')
-rw-r--r--Objects/listobject.c23
1 files changed, 18 insertions, 5 deletions
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 3d4a187..fa26444 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -208,6 +208,19 @@ PyList_Size(PyObject *op)
return Py_SIZE(op);
}
+static inline int
+valid_index(Py_ssize_t i, Py_ssize_t limit)
+{
+ /* The cast to size_t lets us use just a single comparison
+ to check whether i is in the range: 0 <= i < limit.
+
+ See: Section 14.2 "Bounds Checking" in the Agner Fog
+ optimization manual found at:
+ https://www.agner.org/optimize/optimizing_cpp.pdf
+ */
+ return (size_t) i < (size_t) limit;
+}
+
static PyObject *indexerr = NULL;
PyObject *
@@ -217,7 +230,7 @@ PyList_GetItem(PyObject *op, Py_ssize_t i)
PyErr_BadInternalCall();
return NULL;
}
- if (i < 0 || i >= Py_SIZE(op)) {
+ if (!valid_index(i, Py_SIZE(op))) {
if (indexerr == NULL) {
indexerr = PyUnicode_FromString(
"list index out of range");
@@ -240,7 +253,7 @@ PyList_SetItem(PyObject *op, Py_ssize_t i,
PyErr_BadInternalCall();
return -1;
}
- if (i < 0 || i >= Py_SIZE(op)) {
+ if (!valid_index(i, Py_SIZE(op))) {
Py_XDECREF(newitem);
PyErr_SetString(PyExc_IndexError,
"list assignment index out of range");
@@ -426,7 +439,7 @@ list_contains(PyListObject *a, PyObject *el)
static PyObject *
list_item(PyListObject *a, Py_ssize_t i)
{
- if (i < 0 || i >= Py_SIZE(a)) {
+ if (!valid_index(i, Py_SIZE(a))) {
if (indexerr == NULL) {
indexerr = PyUnicode_FromString(
"list index out of range");
@@ -749,7 +762,7 @@ list_inplace_repeat(PyListObject *self, Py_ssize_t n)
static int
list_ass_item(PyListObject *a, Py_ssize_t i, PyObject *v)
{
- if (i < 0 || i >= Py_SIZE(a)) {
+ if (!valid_index(i, Py_SIZE(a))) {
PyErr_SetString(PyExc_IndexError,
"list assignment index out of range");
return -1;
@@ -996,7 +1009,7 @@ list_pop_impl(PyListObject *self, Py_ssize_t index)
}
if (index < 0)
index += Py_SIZE(self);
- if (index < 0 || index >= Py_SIZE(self)) {
+ if (!valid_index(index, Py_SIZE(self))) {
PyErr_SetString(PyExc_IndexError, "pop index out of range");
return NULL;
}