[Python-checkins] r42899 - in python/trunk: Doc/api/abstract.tex Doc/lib/liboperator.tex Doc/ref/ref3.tex Include/abstract.h Include/object.h Lib/test/test_index.py 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

guido.van.rossum python-checkins at python.org
Tue Mar 7 19:51:13 CET 2006


Author: guido.van.rossum
Date: Tue Mar  7 19:50:55 2006
New Revision: 42899

Added:
   python/trunk/Lib/test/test_index.py   (contents, props changed)
Modified:
   python/trunk/Doc/api/abstract.tex
   python/trunk/Doc/lib/liboperator.tex
   python/trunk/Doc/ref/ref3.tex
   python/trunk/Include/abstract.h
   python/trunk/Include/object.h
   python/trunk/Modules/arraymodule.c
   python/trunk/Modules/mmapmodule.c
   python/trunk/Modules/operator.c
   python/trunk/Objects/abstract.c
   python/trunk/Objects/classobject.c
   python/trunk/Objects/intobject.c
   python/trunk/Objects/listobject.c
   python/trunk/Objects/longobject.c
   python/trunk/Objects/stringobject.c
   python/trunk/Objects/tupleobject.c
   python/trunk/Objects/typeobject.c
   python/trunk/Objects/unicodeobject.c
   python/trunk/Python/ceval.c
Log:
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).


Modified: python/trunk/Doc/api/abstract.tex
==============================================================================
--- python/trunk/Doc/api/abstract.tex	(original)
+++ python/trunk/Doc/api/abstract.tex	Tue Mar  7 19:50:55 2006
@@ -346,6 +346,7 @@
   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 @@
   \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}}
 

Modified: python/trunk/Doc/lib/liboperator.tex
==============================================================================
--- python/trunk/Doc/lib/liboperator.tex	(original)
+++ python/trunk/Doc/lib/liboperator.tex	Tue Mar  7 19:50:55 2006
@@ -171,6 +171,11 @@
 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:
 

Modified: python/trunk/Doc/ref/ref3.tex
==============================================================================
--- python/trunk/Doc/ref/ref3.tex	(original)
+++ python/trunk/Doc/ref/ref3.tex	Tue Mar  7 19:50:55 2006
@@ -1978,6 +1978,13 @@
 \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

Modified: python/trunk/Include/abstract.h
==============================================================================
--- python/trunk/Include/abstract.h	(original)
+++ python/trunk/Include/abstract.h	Tue Mar  7 19:50:55 2006
@@ -748,6 +748,14 @@
 
        */
 
+     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);
 
        /*

Modified: python/trunk/Include/object.h
==============================================================================
--- python/trunk/Include/object.h	(original)
+++ python/trunk/Include/object.h	Tue Mar  7 19:50:55 2006
@@ -206,6 +206,9 @@
 	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 @@
 /* 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 @@
                              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)

Added: python/trunk/Lib/test/test_index.py
==============================================================================

Modified: python/trunk/Modules/arraymodule.c
==============================================================================
--- python/trunk/Modules/arraymodule.c	(original)
+++ python/trunk/Modules/arraymodule.c	Tue Mar  7 19:50:55 2006
@@ -1569,19 +1569,17 @@
 	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 @@
 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;

Modified: python/trunk/Modules/mmapmodule.c
==============================================================================
--- python/trunk/Modules/mmapmodule.c	(original)
+++ python/trunk/Modules/mmapmodule.c	Tue Mar  7 19:50:55 2006
@@ -815,6 +815,8 @@
 };
 
 
+#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 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 {

Modified: python/trunk/Modules/operator.c
==============================================================================
--- python/trunk/Modules/operator.c	(original)
+++ python/trunk/Modules/operator.c	Tue Mar  7 19:50:55 2006
@@ -130,6 +130,20 @@
 	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 @@
 
 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.")

Modified: python/trunk/Objects/abstract.c
==============================================================================
--- python/trunk/Objects/abstract.c	(original)
+++ python/trunk/Objects/abstract.c	Tue Mar  7 19:50:55 2006
@@ -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 @@
 		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 @@
 		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 @@
 		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 @@
 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 @@
 		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 @@
 	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)
 {

Modified: python/trunk/Objects/classobject.c
==============================================================================
--- python/trunk/Objects/classobject.c	(original)
+++ python/trunk/Objects/classobject.c	Tue Mar  7 19:50:55 2006
@@ -1733,6 +1733,43 @@
 	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 @@
 	(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 = {

Modified: python/trunk/Objects/intobject.c
==============================================================================
--- python/trunk/Objects/intobject.c	(original)
+++ python/trunk/Objects/intobject.c	Tue Mar  7 19:50:55 2006
@@ -1069,6 +1069,7 @@
 	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 = {

Modified: python/trunk/Objects/listobject.c
==============================================================================
--- python/trunk/Objects/listobject.c	(original)
+++ python/trunk/Objects/listobject.c	Tue Mar  7 19:50:55 2006
@@ -2452,11 +2452,14 @@
 "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 @@
 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)

Modified: python/trunk/Objects/longobject.c
==============================================================================
--- python/trunk/Objects/longobject.c	(original)
+++ python/trunk/Objects/longobject.c	Tue Mar  7 19:50:55 2006
@@ -241,12 +241,8 @@
 	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 @@
  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 @@
 	long_true_divide,		/* nb_true_divide */
 	0,				/* nb_inplace_floor_divide */
 	0,				/* nb_inplace_true_divide */
+	(lenfunc)long_index,            /* nb_index */
 };
 
 PyTypeObject PyLong_Type = {

Modified: python/trunk/Objects/stringobject.c
==============================================================================
--- python/trunk/Objects/stringobject.c	(original)
+++ python/trunk/Objects/stringobject.c	Tue Mar  7 19:50:55 2006
@@ -1187,16 +1187,19 @@
 	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;

Modified: python/trunk/Objects/tupleobject.c
==============================================================================
--- python/trunk/Objects/tupleobject.c	(original)
+++ python/trunk/Objects/tupleobject.c	Tue Mar  7 19:50:55 2006
@@ -584,11 +584,14 @@
 	(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)

Modified: python/trunk/Objects/typeobject.c
==============================================================================
--- python/trunk/Objects/typeobject.c	(original)
+++ python/trunk/Objects/typeobject.c	Tue Mar  7 19:50:55 2006
@@ -3051,6 +3051,9 @@
 			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 @@
 	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 @@
 	       "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,

Modified: python/trunk/Objects/unicodeobject.c
==============================================================================
--- python/trunk/Objects/unicodeobject.c	(original)
+++ python/trunk/Objects/unicodeobject.c	Tue Mar  7 19:50:55 2006
@@ -6460,11 +6460,14 @@
     (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)

Modified: python/trunk/Python/ceval.c
==============================================================================
--- python/trunk/Python/ceval.c	(original)
+++ python/trunk/Python/ceval.c	Tue Mar  7 19:50:55 2006
@@ -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;


More information about the Python-checkins mailing list