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 *
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");
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");
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");
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;
}
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;
}