Skip to content

Commit f1aa8ae

Browse files
authored
Micro-optimize list index range checks (GH-9784)
1 parent 1d26c72 commit f1aa8ae

File tree

1 file changed

+18
-5
lines changed

1 file changed

+18
-5
lines changed

Objects/listobject.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,19 @@ PyList_Size(PyObject *op)
208208
return Py_SIZE(op);
209209
}
210210

211+
static inline int
212+
valid_index(Py_ssize_t i, Py_ssize_t limit)
213+
{
214+
/* The cast to size_t lets us use just a single comparison
215+
to check whether i is in the range: 0 <= i < limit.
216+
217+
See: Section 14.2 "Bounds Checking" in the Agner Fog
218+
optimization manual found at:
219+
https://www.agner.org/optimize/optimizing_cpp.pdf
220+
*/
221+
return (size_t) i < (size_t) limit;
222+
}
223+
211224
static PyObject *indexerr = NULL;
212225

213226
PyObject *
@@ -217,7 +230,7 @@ PyList_GetItem(PyObject *op, Py_ssize_t i)
217230
PyErr_BadInternalCall();
218231
return NULL;
219232
}
220-
if (i < 0 || i >= Py_SIZE(op)) {
233+
if (!valid_index(i, Py_SIZE(op))) {
221234
if (indexerr == NULL) {
222235
indexerr = PyUnicode_FromString(
223236
"list index out of range");
@@ -240,7 +253,7 @@ PyList_SetItem(PyObject *op, Py_ssize_t i,
240253
PyErr_BadInternalCall();
241254
return -1;
242255
}
243-
if (i < 0 || i >= Py_SIZE(op)) {
256+
if (!valid_index(i, Py_SIZE(op))) {
244257
Py_XDECREF(newitem);
245258
PyErr_SetString(PyExc_IndexError,
246259
"list assignment index out of range");
@@ -426,7 +439,7 @@ list_contains(PyListObject *a, PyObject *el)
426439
static PyObject *
427440
list_item(PyListObject *a, Py_ssize_t i)
428441
{
429-
if (i < 0 || i >= Py_SIZE(a)) {
442+
if (!valid_index(i, Py_SIZE(a))) {
430443
if (indexerr == NULL) {
431444
indexerr = PyUnicode_FromString(
432445
"list index out of range");
@@ -749,7 +762,7 @@ list_inplace_repeat(PyListObject *self, Py_ssize_t n)
749762
static int
750763
list_ass_item(PyListObject *a, Py_ssize_t i, PyObject *v)
751764
{
752-
if (i < 0 || i >= Py_SIZE(a)) {
765+
if (!valid_index(i, Py_SIZE(a))) {
753766
PyErr_SetString(PyExc_IndexError,
754767
"list assignment index out of range");
755768
return -1;
@@ -996,7 +1009,7 @@ list_pop_impl(PyListObject *self, Py_ssize_t index)
9961009
}
9971010
if (index < 0)
9981011
index += Py_SIZE(self);
999-
if (index < 0 || index >= Py_SIZE(self)) {
1012+
if (!valid_index(index, Py_SIZE(self))) {
10001013
PyErr_SetString(PyExc_IndexError, "pop index out of range");
10011014
return NULL;
10021015
}

0 commit comments

Comments
 (0)