Checking in the code for PEP 357.
This was mostly written by Travis Oliphant.
I've inspected it all; Neal Norwitz and MvL have also looked at it
(in an earlier incarnation).
diff --git a/Python/ceval.c b/Python/ceval.c
index b069c77..e7fb875 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3916,9 +3916,10 @@
return result;
}
-/* Extract a slice index from a PyInt or PyLong, and store in *pi.
- Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX,
- and silently boost values less than -PY_SSIZE_T_MAX to 0.
+/* Extract a slice index from a PyInt or PyLong or an object with the
+ nb_index slot defined, and store in *pi.
+ Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX,
+ and silently boost values less than -PY_SSIZE_T_MAX-1 to -PY_SSIZE_T_MAX-1.
Return 0 on error, 1 on success.
*/
/* Note: If v is NULL, return success without storing into *pi. This
@@ -3932,46 +3933,18 @@
Py_ssize_t x;
if (PyInt_Check(v)) {
x = PyInt_AsLong(v);
- } else if (PyLong_Check(v)) {
- x = PyInt_AsSsize_t(v);
- if (x==-1 && PyErr_Occurred()) {
- PyObject *long_zero;
- int cmp;
-
- if (!PyErr_ExceptionMatches(
- PyExc_OverflowError)) {
- /* It's not an overflow error, so just
- signal an error */
- return 0;
- }
-
- /* Clear the OverflowError */
- PyErr_Clear();
-
- /* It's an overflow error, so we need to
- check the sign of the long integer,
- set the value to PY_SSIZE_T_MAX or
- -PY_SSIZE_T_MAX, and clear the error. */
-
- /* Create a long integer with a value of 0 */
- long_zero = PyLong_FromLong(0L);
- if (long_zero == NULL)
- return 0;
-
- /* Check sign */
- cmp = PyObject_RichCompareBool(v, long_zero,
- Py_GT);
- Py_DECREF(long_zero);
- if (cmp < 0)
- return 0;
- else if (cmp)
- x = PY_SSIZE_T_MAX;
- else
- x = -PY_SSIZE_T_MAX;
- }
- } else {
+ }
+ else if (v->ob_type->tp_as_number &&
+ PyType_HasFeature(v->ob_type, Py_TPFLAGS_HAVE_INDEX)
+ && v->ob_type->tp_as_number->nb_index) {
+ x = v->ob_type->tp_as_number->nb_index(v);
+ if (x == -1 && PyErr_Occurred())
+ return 0;
+ }
+ else {
PyErr_SetString(PyExc_TypeError,
- "slice indices must be integers or None");
+ "slice indices must be integers or "
+ "None or have an __index__ method");
return 0;
}
*pi = x;
@@ -3979,8 +3952,11 @@
return 1;
}
-#undef ISINT
-#define ISINT(x) ((x) == NULL || PyInt_Check(x) || PyLong_Check(x))
+#undef ISINDEX
+#define ISINDEX(x) ((x) == NULL || PyInt_Check(x) || PyLong_Check(x) || \
+ ((x)->ob_type->tp_as_number && \
+ PyType_HasFeature((x)->ob_type, Py_TPFLAGS_HAVE_INDEX) \
+ && (x)->ob_type->tp_as_number->nb_index))
static PyObject *
apply_slice(PyObject *u, PyObject *v, PyObject *w) /* return u[v:w] */
@@ -3988,7 +3964,7 @@
PyTypeObject *tp = u->ob_type;
PySequenceMethods *sq = tp->tp_as_sequence;
- if (sq && sq->sq_slice && ISINT(v) && ISINT(w)) {
+ if (sq && sq->sq_slice && ISINDEX(v) && ISINDEX(w)) {
Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX;
if (!_PyEval_SliceIndex(v, &ilow))
return NULL;
@@ -4015,7 +3991,7 @@
PyTypeObject *tp = u->ob_type;
PySequenceMethods *sq = tp->tp_as_sequence;
- if (sq && sq->sq_slice && ISINT(v) && ISINT(w)) {
+ if (sq && sq->sq_slice && ISINDEX(v) && ISINDEX(w)) {
Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX;
if (!_PyEval_SliceIndex(v, &ilow))
return -1;