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).
either the sequence and mapping protocols, the sequence length is
returned. On error, \code{-1} is returned. This is the equivalent
to the Python expression \samp{len(\var{o})}.\bifuncindex{len}
+ \versionadded{2.5}
\end{cfuncdesc}
\samp{float(\var{o})}.\bifuncindex{float}
\end{cfuncdesc}
+\begin{cfuncdesc}{Py_ssize_t}{PyNumber_Index}{PyObject *o}
+ Returns the \var{o} converted to a Py_ssize_t integer on success, or
+ -1 with an exception raised on failure.
+\end{cfuncdesc}
\section{Sequence Protocol \label{sequence}}
Return the bitwise exclusive or of \var{a} and \var{b}.
\end{funcdesc}
+\begin{funcdesc}{index}{a}
+\funcline{__index__}{a}
+Return \var{a} converted to an integer. Equivalent to \var{a}\code{.__index__()}.
+\versionadded{2.5}
+\end{funcdesc}
Operations which work with sequences include:
\function{hex()}\bifuncindex{hex}. Should return a string value.
\end{methoddesc}
+\begin{methoddesc}[numeric object]{__index__}{self}
+Called to implement operator.index(). Also called whenever Python
+needs an integer object (such as in slicing). Must return an integer
+(int or long).
+\versionadded{2.5}
+\end{methoddesc}
+
\begin{methoddesc}[numeric object]{__coerce__}{self, other}
Called to implement ``mixed-mode'' numeric arithmetic. Should either
return a 2-tuple containing \var{self} and \var{other} converted to
*/
+ PyAPI_FUNC(Py_ssize_t) PyNumber_Index(PyObject *);
+
+ /*
+ Returns the object converted to Py_ssize_t on success
+ or -1 with an error raised on failure.
+ */
+
+
PyAPI_FUNC(PyObject *) PyNumber_Int(PyObject *o);
/*
binaryfunc nb_true_divide;
binaryfunc nb_inplace_floor_divide;
binaryfunc nb_inplace_true_divide;
+
+ /* Added in release 2.5 */
+ lenfunc nb_index;
} PyNumberMethods;
typedef struct {
/* Objects support garbage collection (see objimp.h) */
#define Py_TPFLAGS_HAVE_GC (1L<<14)
-/* These two bits are preserved for Stackless Python, next after this is 16 */
+/* These two bits are preserved for Stackless Python, next after this is 17 */
#ifdef STACKLESS
#define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION (3L<<15)
#else
#define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION 0
#endif
+/* Objects support nb_index in PyNumberMethods */
+#define Py_TPFLAGS_HAVE_INDEX (1L<<17)
+
#define Py_TPFLAGS_DEFAULT ( \
Py_TPFLAGS_HAVE_GETCHARBUFFER | \
Py_TPFLAGS_HAVE_SEQUENCE_IN | \
Py_TPFLAGS_HAVE_ITER | \
Py_TPFLAGS_HAVE_CLASS | \
Py_TPFLAGS_HAVE_STACKLESS_EXTENSION | \
+ Py_TPFLAGS_HAVE_INDEX | \
0)
#define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0)
return s;
}
+#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
+
static PyObject*
array_subscr(arrayobject* self, PyObject* item)
{
- if (PyInt_Check(item)) {
- Py_ssize_t i = PyInt_AS_LONG(item);
- if (i < 0)
- i += self->ob_size;
- return array_item(self, i);
- }
- else if (PyLong_Check(item)) {
- Py_ssize_t i = PyInt_AsSsize_t(item);
- if (i == -1 && PyErr_Occurred())
+ PyNumberMethods *nb = item->ob_type->tp_as_number;
+ if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
+ Py_ssize_t i = nb->nb_index(item);
+ if (i==-1 && PyErr_Occurred()) {
return NULL;
+ }
if (i < 0)
i += self->ob_size;
return array_item(self, i);
static int
array_ass_subscr(arrayobject* self, PyObject* item, PyObject* value)
{
- if (PyInt_Check(item)) {
- Py_ssize_t i = PyInt_AS_LONG(item);
- if (i < 0)
- i += self->ob_size;
- return array_ass_item(self, i, value);
- }
- else if (PyLong_Check(item)) {
- Py_ssize_t i = PyInt_AsSsize_t(item);
- if (i == -1 && PyErr_Occurred())
+ PyNumberMethods *nb = item->ob_type->tp_as_number;
+ if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
+ Py_ssize_t i = nb->nb_index(item);
+ if (i==-1 && PyErr_Occurred())
return -1;
if (i < 0)
i += self->ob_size;
};
+#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
+
/* extract the map size from the given PyObject
Returns -1 on error, with an appropriate Python exception raised. On
static Py_ssize_t
_GetMapSize(PyObject *o)
{
- if (PyInt_Check(o)) {
- long i = PyInt_AsLong(o);
- if (PyErr_Occurred())
+ PyNumberMethods *nb = o->ob_type->tp_as_number;
+ if (nb != NULL && HASINDEX(o) && nb->nb_index != NULL) {
+ Py_ssize_t i = nb->nb_index(o);
+ if (i==-1 && PyErr_Occurred())
return -1;
if (i < 0)
goto onnegoverflow;
- return i;
- }
- else if (PyLong_Check(o)) {
- Py_ssize_t i = PyInt_AsSsize_t(o);
- if (PyErr_Occurred()) {
- /* yes negative overflow is mistaken for positive overflow
- but not worth the trouble to check sign of 'i' */
- if (PyErr_ExceptionMatches(PyExc_OverflowError))
- goto onposoverflow;
- else
- return -1;
- }
- if (i < 0)
- goto onnegoverflow;
+ if (i==PY_SSIZE_T_MAX)
+ goto onposoverflow;
return i;
}
else {
return NULL;
}
+static PyObject *
+op_index(PyObject *s, PyObject *a)
+{
+ Py_ssize_t i;
+ PyObject *a1;
+ if (!PyArg_UnpackTuple(a,"index", 1, 1, &a1))
+ return NULL;
+ i = PyNumber_Index(a1);
+ if (i == -1 && PyErr_Occurred())
+ return NULL;
+ else
+ return PyInt_FromSsize_t(i);
+}
+
static PyObject*
is_(PyObject *s, PyObject *a)
{
spam1(is_, "is_(a, b) -- Same as a is b.")
spam1(is_not, "is_not(a, b) -- Same as a is not b.")
+spam2(index, __index__, "index(a) -- Same as a.__index__()")
spam2(add,__add__, "add(a, b) -- Same as a + b.")
spam2(sub,__sub__, "sub(a, b) -- Same as a - b.")
spam2(mul,__mul__, "mul(a, b) -- Same as a * b.")
#define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \
Py_TPFLAGS_CHECKTYPES)
+#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
+
/* Shorthands to return certain errors */
static PyObject *
return m->mp_subscript(o, key);
if (o->ob_type->tp_as_sequence) {
- if (PyInt_Check(key))
- return PySequence_GetItem(o, PyInt_AsLong(key));
- else if (PyLong_Check(key)) {
- long key_value = PyLong_AsLong(key);
+ PyNumberMethods *nb = key->ob_type->tp_as_number;
+ if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) {
+ Py_ssize_t key_value = nb->nb_index(key);
if (key_value == -1 && PyErr_Occurred())
return NULL;
return PySequence_GetItem(o, key_value);
return m->mp_ass_subscript(o, key, value);
if (o->ob_type->tp_as_sequence) {
- if (PyInt_Check(key))
- return PySequence_SetItem(o, PyInt_AsLong(key), value);
- else if (PyLong_Check(key)) {
- long key_value = PyLong_AsLong(key);
+ PyNumberMethods *nb = key->ob_type->tp_as_number;
+ if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) {
+ Py_ssize_t key_value = nb->nb_index(key);
if (key_value == -1 && PyErr_Occurred())
return -1;
return PySequence_SetItem(o, key_value, value);
return m->mp_ass_subscript(o, key, (PyObject*)NULL);
if (o->ob_type->tp_as_sequence) {
- if (PyInt_Check(key))
- return PySequence_DelItem(o, PyInt_AsLong(key));
- else if (PyLong_Check(key)) {
- long key_value = PyLong_AsLong(key);
+ PyNumberMethods *nb = key->ob_type->tp_as_number;
+ if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) {
+ Py_ssize_t key_value = nb->nb_index(key);
if (key_value == -1 && PyErr_Occurred())
return -1;
return PySequence_DelItem(o, key_value);
static PyObject *
sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n)
{
- long count;
- if (PyInt_Check(n)) {
- count = PyInt_AsLong(n);
- }
- else if (PyLong_Check(n)) {
- count = PyLong_AsLong(n);
+ Py_ssize_t count;
+ PyNumberMethods *nb = n->ob_type->tp_as_number;
+ if (nb != NULL && HASINDEX(n) && nb->nb_index != NULL) {
+ count = nb->nb_index(n);
if (count == -1 && PyErr_Occurred())
return NULL;
}
return type_error(
"can't multiply sequence by non-int");
}
-#if LONG_MAX != INT_MAX
- if (count > INT_MAX) {
- PyErr_SetString(PyExc_ValueError,
- "sequence repeat count too large");
- return NULL;
- }
- else if (count < INT_MIN)
- count = INT_MIN;
- /* XXX Why don't I either
-
- - set count to -1 whenever it's negative (after all,
- sequence repeat usually treats negative numbers
- as zero(); or
-
- - raise an exception when it's less than INT_MIN?
-
- I'm thinking about a hypothetical use case where some
- sequence type might use a negative value as a flag of
- some kind. In those cases I don't want to break the
- code by mapping all negative values to -1. But I also
- don't want to break e.g. []*(-sys.maxint), which is
- perfectly safe, returning []. As a compromise, I do
- map out-of-range negative values.
- */
-#endif
- return (*repeatfunc)(seq, (int)count);
+ return (*repeatfunc)(seq, count);
}
PyObject *
return x;
}
+/* Return a Py_ssize_t integer from the object item */
+Py_ssize_t
+PyNumber_Index(PyObject *item)
+{
+ Py_ssize_t value = -1;
+ PyNumberMethods *nb = item->ob_type->tp_as_number;
+ if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
+ value = nb->nb_index(item);
+ }
+ else {
+ PyErr_SetString(PyExc_IndexError,
+ "object cannot be interpreted as an index");
+ }
+ return value;
+}
+
PyObject *
PyNumber_Int(PyObject *o)
{
return outcome > 0;
}
+static Py_ssize_t
+instance_index(PyInstanceObject *self)
+{
+ PyObject *func, *res;
+ Py_ssize_t outcome;
+ static PyObject *indexstr = NULL;
+
+ if (indexstr == NULL) {
+ indexstr = PyString_InternFromString("__index__");
+ if (indexstr == NULL)
+ return -1;
+ }
+ if ((func = instance_getattr(self, indexstr)) == NULL) {
+ if (!PyErr_ExceptionMatches(PyExc_AttributeError))
+ return -1;
+ PyErr_Clear();
+ PyErr_SetString(PyExc_TypeError,
+ "object cannot be interpreted as an index");
+ return -1;
+ }
+ res = PyEval_CallObject(func, (PyObject *)NULL);
+ Py_DECREF(func);
+ if (res == NULL)
+ return -1;
+ if (PyInt_Check(res) || PyLong_Check(res)) {
+ outcome = res->ob_type->tp_as_number->nb_index(res);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "__index__ must return an int or a long");
+ outcome = -1;
+ }
+ Py_DECREF(res);
+ return outcome;
+}
+
+
UNARY(instance_invert, "__invert__")
UNARY(instance_int, "__int__")
UNARY(instance_long, "__long__")
(binaryfunc)instance_truediv, /* nb_true_divide */
(binaryfunc)instance_ifloordiv, /* nb_inplace_floor_divide */
(binaryfunc)instance_itruediv, /* nb_inplace_true_divide */
+ (lenfunc)instance_index, /* nb_index */
};
PyTypeObject PyInstance_Type = {
int_true_divide, /* nb_true_divide */
0, /* nb_inplace_floor_divide */
0, /* nb_inplace_true_divide */
+ (lenfunc)PyInt_AsSsize_t, /* nb_index */
};
PyTypeObject PyInt_Type = {
"list() -> new list\n"
"list(sequence) -> new list initialized from sequence's items");
+#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
+
static PyObject *
list_subscript(PyListObject* self, PyObject* item)
{
- if (PyInt_Check(item) || PyLong_Check(item)) {
- Py_ssize_t i = PyInt_AsSsize_t(item);
+ PyNumberMethods *nb = item->ob_type->tp_as_number;
+ if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
+ Py_ssize_t i = nb->nb_index(item);
if (i == -1 && PyErr_Occurred())
return NULL;
if (i < 0)
static int
list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value)
{
- if (PyInt_Check(item)) {
- Py_ssize_t i = PyInt_AS_LONG(item);
- if (i < 0)
- i += PyList_GET_SIZE(self);
- return list_ass_item(self, i, value);
- }
- else if (PyLong_Check(item)) {
- Py_ssize_t i = PyInt_AsSsize_t(item);
+ PyNumberMethods *nb = item->ob_type->tp_as_number;
+ if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
+ Py_ssize_t i = nb->nb_index(item);
if (i == -1 && PyErr_Occurred())
return -1;
if (i < 0)
return -1;
}
-/* Get a Py_ssize_t from a long int object.
- Returns -1 and sets an error condition if overflow occurs. */
-
-Py_ssize_t
-_PyLong_AsSsize_t(PyObject *vv)
-{
+static Py_ssize_t
+_long_as_ssize_t(PyObject *vv) {
register PyLongObject *v;
size_t x, prev;
Py_ssize_t i;
overflow:
PyErr_SetString(PyExc_OverflowError,
"long int too large to convert to int");
- return -1;
+ if (sign > 0)
+ return PY_SSIZE_T_MAX;
+ else
+ return -PY_SSIZE_T_MAX-1;
+}
+
+/* Get a Py_ssize_t from a long int object.
+ Returns -1 and sets an error condition if overflow occurs. */
+
+Py_ssize_t
+_PyLong_AsSsize_t(PyObject *vv)
+{
+ Py_ssize_t x;
+
+ x = _long_as_ssize_t(vv);
+ if (PyErr_Occurred()) return -1;
+ return x;
+}
+
+
+/* Get a Py_ssize_t from a long int object.
+ 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.
+*/
+
+static Py_ssize_t
+long_index(PyObject *vv)
+{
+ Py_ssize_t x;
+
+ x = _long_as_ssize_t(vv);
+ if (PyErr_Occurred()) {
+ /* If overflow error, ignore the error */
+ if (x != -1) {
+ PyErr_Clear();
+ }
+ }
+ return x;
}
/* Get a C unsigned long int from a long int object.
long_true_divide, /* nb_true_divide */
0, /* nb_inplace_floor_divide */
0, /* nb_inplace_true_divide */
+ (lenfunc)long_index, /* nb_index */
};
PyTypeObject PyLong_Type = {
return x;
}
+#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
+
static PyObject*
string_subscript(PyStringObject* self, PyObject* item)
{
- if (PyInt_Check(item) || PyLong_Check(item)) {
- Py_ssize_t i = PyInt_AsSsize_t(item);
+ PyNumberMethods *nb = item->ob_type->tp_as_number;
+ if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
+ Py_ssize_t i = nb->nb_index(item);
if (i == -1 && PyErr_Occurred())
return NULL;
if (i < 0)
i += PyString_GET_SIZE(self);
- return string_item(self,i);
+ return string_item(self, i);
}
else if (PySlice_Check(item)) {
Py_ssize_t start, stop, step, slicelength, cur, i;
(objobjproc)tuplecontains, /* sq_contains */
};
+#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
+
static PyObject*
tuplesubscript(PyTupleObject* self, PyObject* item)
{
- if (PyInt_Check(item) || PyLong_Check(item)) {
- Py_ssize_t i = PyInt_AsSsize_t(item);
+ PyNumberMethods *nb = item->ob_type->tp_as_number;
+ if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
+ Py_ssize_t i = nb->nb_index(item);
if (i == -1 && PyErr_Occurred())
return NULL;
if (i < 0)
COPYNUM(nb_inplace_true_divide);
COPYNUM(nb_inplace_floor_divide);
}
+ if (base->tp_flags & Py_TPFLAGS_HAVE_INDEX) {
+ COPYNUM(nb_index);
+ }
}
if (type->tp_as_sequence != NULL && base->tp_as_sequence != NULL) {
return result;
}
+
+static Py_ssize_t
+slot_nb_index(PyObject *self)
+{
+ PyObject *func, *args;
+ static PyObject *index_str;
+ Py_ssize_t result = -1;
+
+ func = lookup_maybe(self, "__index__", &index_str);
+ if (func == NULL) {
+ if (!PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError,
+ "object cannot be interpreted as an index");
+ }
+ return -1;
+ }
+ args = PyTuple_New(0);
+ if (args != NULL) {
+ PyObject *temp = PyObject_Call(func, args, NULL);
+ Py_DECREF(args);
+ if (temp != NULL) {
+ if (PyInt_Check(temp) || PyLong_Check(temp)) {
+ result =
+ temp->ob_type->tp_as_number->nb_index(temp);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "__index__ must return an int or a long");
+ result = -1;
+ }
+ Py_DECREF(temp);
+ }
+ }
+ Py_DECREF(func);
+ return result;
+}
+
+
SLOT0(slot_nb_invert, "__invert__")
SLOT1BIN(slot_nb_lshift, nb_lshift, "__lshift__", "__rlshift__")
SLOT1BIN(slot_nb_rshift, nb_rshift, "__rshift__", "__rrshift__")
"oct(x)"),
UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc,
"hex(x)"),
+ NBSLOT("__index__", nb_index, slot_nb_index, wrap_lenfunc,
+ "x[y:z] <==> x[y.__index__():z.__index__()]"),
IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add,
wrap_binaryfunc, "+"),
IBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract,
(objobjproc)PyUnicode_Contains, /*sq_contains*/
};
+#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
+
static PyObject*
unicode_subscript(PyUnicodeObject* self, PyObject* item)
{
- if (PyInt_Check(item) || PyLong_Check(item)) {
- Py_ssize_t i = PyInt_AsSsize_t(item);
+ PyNumberMethods *nb = item->ob_type->tp_as_number;
+ if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
+ Py_ssize_t i = nb->nb_index(item);
if (i == -1 && PyErr_Occurred())
return NULL;
if (i < 0)
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
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;
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] */
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;
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;