]> granicus.if.org Git - python/commitdiff
Checking in the code for PEP 357.
authorGuido van Rossum <guido@python.org>
Tue, 7 Mar 2006 18:50:55 +0000 (18:50 +0000)
committerGuido van Rossum <guido@python.org>
Tue, 7 Mar 2006 18:50:55 +0000 (18:50 +0000)
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).

19 files changed:
Doc/api/abstract.tex
Doc/lib/liboperator.tex
Doc/ref/ref3.tex
Include/abstract.h
Include/object.h
Lib/test/test_index.py [new file with mode: 0644]
Modules/arraymodule.c
Modules/mmapmodule.c
Modules/operator.c
Objects/abstract.c
Objects/classobject.c
Objects/intobject.c
Objects/listobject.c
Objects/longobject.c
Objects/stringobject.c
Objects/tupleobject.c
Objects/typeobject.c
Objects/unicodeobject.c
Python/ceval.c

index c54356327a8938ee811e74d2f5bf15bfc7de9fc0..320275c406ef5317058702167364713fa24fc6b6 100644 (file)
@@ -346,6 +346,7 @@ determination.
   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}
 
 
@@ -689,6 +690,10 @@ determination.
   \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}}
 
index 11e004ab5ded13a8109ba9964c648e7677f15780..41da9b7c5a3651ae0813f6507192ebae5a024adc 100644 (file)
@@ -171,6 +171,11 @@ effect.  This is also known as ``true'' division.
 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:
 
index 5b78f1cb2762089af7aaba67ff83f65e95e6a005..737b8618ec52cf5a815f3a60f5bd8ceeeae3bea7 100644 (file)
@@ -1978,6 +1978,13 @@ Called to implement the built-in functions
 \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
index 73dc91d11b371ea99f261806ec0b62eb8969ecf1..9ec18fa1f26f302c4c9bdc4184d4567af7b4505c 100644 (file)
@@ -748,6 +748,14 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
 
        */
 
+     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);
 
        /*
index 2eb2b44c6588b6e45aec9a59b1b313747211e808..131812f93b2131c7149326591c276f288232d4aa 100644 (file)
@@ -206,6 +206,9 @@ typedef struct {
        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 {
@@ -503,13 +506,16 @@ given type object has a specified feature.
 /* 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 | \
@@ -519,6 +525,7 @@ given type object has a specified feature.
                              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)
diff --git a/Lib/test/test_index.py b/Lib/test/test_index.py
new file mode 100644 (file)
index 0000000..e69de29
index 2318739a957e37cdd8e1fde695af7a5bd9060a1d..1650ff2f3eec0beb11e463756b9c286527c0fb97 100644 (file)
@@ -1569,19 +1569,17 @@ array_repr(arrayobject *a)
        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);
@@ -1626,15 +1624,10 @@ array_subscr(arrayobject* self, PyObject* item)
 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;
index 7c3c3e4e2d4f97f37832d1d2d819cf637ee59e2c..2e34a9f7fd0bc1166183e72647398a8e0646ebbb 100644 (file)
@@ -815,6 +815,8 @@ static PyTypeObject mmap_object_type = {
 };
 
 
+#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
@@ -822,26 +824,15 @@ static PyTypeObject mmap_object_type = {
 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 {
index 1a2ef852b923d41213a7b534e49b9dac828b73da..53144f164fb9881f1ef79965444b1c824e76b4de 100644 (file)
@@ -130,6 +130,20 @@ op_ipow(PyObject *s, PyObject *a)
        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)
 {
@@ -229,6 +243,7 @@ spam1o(isMappingType,
 
 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.")
index 7ded61abe25c3a0d4237b7e3177874de4f43547c..399656ffe0058de83f8638cd97fc5e414bc2679e 100644 (file)
@@ -8,6 +8,8 @@
 #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 *
@@ -119,10 +121,9 @@ PyObject_GetItem(PyObject *o, PyObject *key)
                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);
@@ -148,10 +149,9 @@ PyObject_SetItem(PyObject *o, PyObject *key, PyObject *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);
@@ -180,10 +180,9 @@ PyObject_DelItem(PyObject *o, PyObject *key)
                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);
@@ -647,12 +646,10 @@ PyNumber_Add(PyObject *v, PyObject *w)
 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;
        }
@@ -660,32 +657,7 @@ sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n)
                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 *
@@ -960,6 +932,22 @@ int_from_string(const char *s, Py_ssize_t len)
        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)
 {
index 34afb9ef0fb985c72326cc78425a0058addb2891..037252d06a4ba187bcec2a90c6da76fe80f9038c 100644 (file)
@@ -1733,6 +1733,43 @@ instance_nonzero(PyInstanceObject *self)
        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__")
@@ -2052,6 +2089,7 @@ static PyNumberMethods instance_as_number = {
        (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 = {
index d7a64be604008dac1dda547dd3f0bdb4c3e889e4..86e2e8c08fbca78a34f2316f06d3ed8f1bcabad2 100644 (file)
@@ -1069,6 +1069,7 @@ static PyNumberMethods int_as_number = {
        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 = {
index 0ff61e279306c704d677a0182b06b2037d583e96..966d659efa390a1d011b60c41fef802484193f81 100644 (file)
@@ -2452,11 +2452,14 @@ PyDoc_STRVAR(list_doc,
 "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)
@@ -2503,14 +2506,9 @@ list_subscript(PyListObject* self, PyObject* item)
 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)
index 903265685fbc92476ed1eb0a933dab3c28615640..e47c292c9506f80b6b6edc0034526a463c980b0f 100644 (file)
@@ -241,12 +241,8 @@ PyLong_AsLong(PyObject *vv)
        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;
@@ -282,7 +278,45 @@ _PyLong_AsSsize_t(PyObject *vv)
  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.
@@ -3131,6 +3165,7 @@ static PyNumberMethods long_as_number = {
        long_true_divide,               /* nb_true_divide */
        0,                              /* nb_inplace_floor_divide */
        0,                              /* nb_inplace_true_divide */
+       (lenfunc)long_index,            /* nb_index */
 };
 
 PyTypeObject PyLong_Type = {
index e2b7603b5a233094bbd29679822744a4fdd76c98..16d542ae070322a518897485b5a3d3056cb34650 100644 (file)
@@ -1187,16 +1187,19 @@ string_hash(PyStringObject *a)
        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;
index c0383a1e0970f67ce8e6d7581011f91ef03a74b3..384b355a10eb0d5798113ea1facfcb044503de76 100644 (file)
@@ -584,11 +584,14 @@ static PySequenceMethods tuple_as_sequence = {
        (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)
index 9837e38e429000a0aa0c432e57e46c65cfb3cd20..681fb21ab8ca029ab8db5e58b0fc7862e879752a 100644 (file)
@@ -3051,6 +3051,9 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base)
                        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) {
@@ -4344,6 +4347,44 @@ slot_nb_nonzero(PyObject *self)
        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__")
@@ -5069,6 +5110,8 @@ static slotdef slotdefs[] = {
               "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,
index 4146f1d880ea853eacb6eac04e72c976fd1a706b..a0d3de97f1e257bfc2c7144cc1ce1d71e8e13e6e 100644 (file)
@@ -6460,11 +6460,14 @@ static PySequenceMethods unicode_as_sequence = {
     (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)
index b069c774249f97729b9903c5ea8a0f8cf50ed1a2..e7fb875b3c9a563ab33b3c34b93d6bbe4befc972 100644 (file)
@@ -3916,9 +3916,10 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
        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 @@ _PyEval_SliceIndex(PyObject *v, Py_ssize_t *pi)
                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 @@ _PyEval_SliceIndex(PyObject *v, Py_ssize_t *pi)
        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 @@ 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;
@@ -4015,7 +3991,7 @@ assign_slice(PyObject *u, PyObject *v, PyObject *w, PyObject *x)
        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;