From d1526787cce0434dc86f2be36dea9b295b85ba57 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 9 Oct 2018 20:31:45 -0700 Subject: [PATCH 1/2] Optimize list_item --- Objects/listobject.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 3d4a187f692902..3b4c69134df66f 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -423,10 +423,18 @@ list_contains(PyListObject *a, PyObject *el) return cmp; } +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 */ + return (size_t) i < (size_t) limit; +} + 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"); From 65b589b983e4aedb040656589bab6f9f82750755 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 9 Oct 2018 20:45:50 -0700 Subject: [PATCH 2/2] Convert the other range checks as well --- Objects/listobject.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 3b4c69134df66f..fa26444f847fc4 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"); @@ -423,14 +436,6 @@ list_contains(PyListObject *a, PyObject *el) return cmp; } -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 */ - return (size_t) i < (size_t) limit; -} - static PyObject * list_item(PyListObject *a, Py_ssize_t i) { @@ -757,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; @@ -1004,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; }