[Python-checkins] CVS: python/dist/src/Objects abstract.c,2.73,2.74 classobject.c,2.145,2.146 typeobject.c,2.57,2.58

Tim Peters tim_one@users.sourceforge.net
Fri, 07 Sep 2001 21:00:14 -0700


Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv1044/python/Objects

Modified Files:
	abstract.c classobject.c typeobject.c 
Log Message:
Generalize operator.indexOf (PySequence_Index) to work with any
iterable object.  I'm not sure how that got overlooked before!

Got rid of the internal _PySequence_IterContains, introduced a new
internal _PySequence_IterSearch, and rewrote all the iteration-based
"count of", "index of", and "is the object in it or not?" routines to
just call the new function.  I suppose it's slower this way, but the
code duplication was getting depressing.


Index: abstract.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/abstract.c,v
retrieving revision 2.73
retrieving revision 2.74
diff -C2 -d -r2.73 -r2.74
*** abstract.c	2001/09/07 20:20:11	2.73
--- abstract.c	2001/09/08 04:00:12	2.74
***************
*** 1373,1395 ****
  }
  
! /* Return # of times o appears in s. */
  int
! PySequence_Count(PyObject *s, PyObject *o)
  {
! 	int n;  /* running count of o hits */
! 	PyObject *it;  /* iter(s) */
  
! 	if (s == NULL || o == NULL) {
  		null_error();
  		return -1;
  	}
  
! 	it = PyObject_GetIter(s);
  	if (it == NULL) {
! 		type_error(".count() requires iterable argument");
  		return -1;
  	}
  
! 	n = 0;
  	for (;;) {
  		int cmp;
--- 1373,1401 ----
  }
  
! /* Iterate over seq.  Result depends on the operation:
!    PY_ITERSEARCH_COUNT:  -1 if error, else # of times obj appears in seq.
!    PY_ITERSEARCH_INDEX:  0-based index of first occurence of obj in seq;
!    	set ValueError and return -1 if none found; also return -1 on error.
!    Py_ITERSEARCH_CONTAINS:  return 1 if obj in seq, else 0; -1 on error.
! */
  int
! _PySequence_IterSearch(PyObject *seq, PyObject *obj, int operation)
  {
! 	int n;
! 	int wrapped;  /* for PY_ITERSEARCH_INDEX, true iff n wrapped around */
! 	PyObject *it;  /* iter(seq) */
  
! 	if (seq == NULL || obj == NULL) {
  		null_error();
  		return -1;
  	}
  
! 	it = PyObject_GetIter(seq);
  	if (it == NULL) {
! 		type_error("iterable argument required");
  		return -1;
  	}
  
! 	n = wrapped = 0;
  	for (;;) {
  		int cmp;
***************
*** 1400,1458 ****
  			break;
  		}
! 		cmp = PyObject_RichCompareBool(o, item, Py_EQ);
  		Py_DECREF(item);
  		if (cmp < 0)
  			goto Fail;
  		if (cmp > 0) {
! 			if (n == INT_MAX) {
! 				PyErr_SetString(PyExc_OverflowError,
  				                "count exceeds C int size");
! 				goto Fail;
  			}
! 			n++;
  		}
  	}
- 	Py_DECREF(it);
- 	return n;
  
  Fail:
  	Py_DECREF(it);
! 	return -1;
  }
  
! /* Return -1 if error; 1 if ob in seq; 0 if ob not in seq.
!  * Always uses the iteration protocol, and only Py_EQ comparison.
!  */
  int
! _PySequence_IterContains(PyObject *seq, PyObject *ob)
  {
! 	int result;
! 	PyObject *it = PyObject_GetIter(seq);
! 	if (it == NULL) {
! 		PyErr_SetString(PyExc_TypeError,
! 			"'in' or 'not in' needs iterable right argument");
! 		return -1;
! 	}
! 
! 	for (;;) {
! 		int cmp;
! 		PyObject *item = PyIter_Next(it);
! 		if (item == NULL) {
! 			result = PyErr_Occurred() ? -1 : 0;
! 			break;
! 		}
! 		cmp = PyObject_RichCompareBool(ob, item, Py_EQ);
! 		Py_DECREF(item);
! 		if (cmp == 0)
! 			continue;
! 		result = cmp > 0 ? 1 : -1;
! 		break;
! 	}
! 	Py_DECREF(it);
! 	return result;
  }
  
  /* Return -1 if error; 1 if ob in seq; 0 if ob not in seq.
!  * Use sq_contains if possible, else defer to _PySequence_IterContains().
   */
  int
--- 1406,1473 ----
  			break;
  		}
! 
! 		cmp = PyObject_RichCompareBool(obj, item, Py_EQ);
  		Py_DECREF(item);
  		if (cmp < 0)
  			goto Fail;
  		if (cmp > 0) {
! 			switch (operation) {
! 			case PY_ITERSEARCH_COUNT:
! 				++n;
! 				if (n <= 0) {
! 					PyErr_SetString(PyExc_OverflowError,
  				                "count exceeds C int size");
! 					goto Fail;
! 				}
! 				break;
! 
! 			case PY_ITERSEARCH_INDEX:
! 				if (wrapped) {
! 					PyErr_SetString(PyExc_OverflowError,
! 			                	"index exceeds C int size");
! 					goto Fail;
! 				}
! 				goto Done;
! 
! 			case PY_ITERSEARCH_CONTAINS:
! 				n = 1;
! 				goto Done;
! 
! 			default:
! 				assert(!"unknown operation");
  			}
! 		}
! 
! 		if (operation == PY_ITERSEARCH_INDEX) {
! 			++n;
! 			if (n <= 0)
! 				wrapped = 1;
  		}
  	}
  
+ 	if (operation != PY_ITERSEARCH_INDEX)
+ 		goto Done;
+ 
+ 	PyErr_SetString(PyExc_ValueError,
+ 		        "sequence.index(x): x not in sequence");
+ 	/* fall into failure code */
  Fail:
+ 	n = -1;
+ 	/* fall through */
+ Done:
  	Py_DECREF(it);
! 	return n;
! 
  }
  
! /* Return # of times o appears in s. */
  int
! PySequence_Count(PyObject *s, PyObject *o)
  {
! 	return _PySequence_IterSearch(s, o, PY_ITERSEARCH_COUNT);
  }
  
  /* Return -1 if error; 1 if ob in seq; 0 if ob not in seq.
!  * Use sq_contains if possible, else defer to _PySequence_IterSearch().
   */
  int
***************
*** 1464,1468 ****
  			return (*sqm->sq_contains)(seq, ob);
  	}
! 	return _PySequence_IterContains(seq, ob);
  }
  
--- 1479,1483 ----
  			return (*sqm->sq_contains)(seq, ob);
  	}
! 	return _PySequence_IterSearch(seq, ob, PY_ITERSEARCH_CONTAINS);
  }
  
***************
*** 1478,1507 ****
  PySequence_Index(PyObject *s, PyObject *o)
  {
! 	int l, i, cmp, err;
! 	PyObject *item;
! 
! 	if (s == NULL || o == NULL) {
! 		null_error();
! 		return -1;
! 	}
! 	
! 	l = PySequence_Size(s);
! 	if (l < 0)
! 		return -1;
! 
! 	for (i = 0; i < l; i++) {
! 		item = PySequence_GetItem(s, i);
! 		if (item == NULL)
! 			return -1;
! 		err = PyObject_Cmp(item, o, &cmp);
! 		Py_DECREF(item);
! 		if (err < 0)
! 			return err;
! 		if (cmp == 0)
! 			return i;
! 	}
! 
! 	PyErr_SetString(PyExc_ValueError, "sequence.index(x): x not in list");
! 	return -1;
  }
  
--- 1493,1497 ----
  PySequence_Index(PyObject *s, PyObject *o)
  {
! 	return _PySequence_IterSearch(s, o, PY_ITERSEARCH_INDEX);
  }
  

Index: classobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/classobject.c,v
retrieving revision 2.145
retrieving revision 2.146
diff -C2 -d -r2.145 -r2.146
*** classobject.c	2001/09/07 21:08:32	2.145
--- classobject.c	2001/09/08 04:00:12	2.146
***************
*** 1225,1229 ****
  		 */
  		PyErr_Clear();
! 		return _PySequence_IterContains((PyObject *)inst, member);
  	}
  	else
--- 1225,1230 ----
  		 */
  		PyErr_Clear();
! 		return _PySequence_IterSearch((PyObject *)inst, member,
! 					      PY_ITERSEARCH_CONTAINS);
  	}
  	else

Index: typeobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/typeobject.c,v
retrieving revision 2.57
retrieving revision 2.58
diff -C2 -d -r2.57 -r2.58
*** typeobject.c	2001/09/07 18:52:13	2.57
--- typeobject.c	2001/09/08 04:00:12	2.58
***************
*** 2560,2564 ****
  	else {
  		PyErr_Clear();
! 		return _PySequence_IterContains(self, value);
  	}
  }
--- 2560,2565 ----
  	else {
  		PyErr_Clear();
! 		return _PySequence_IterSearch(self, value,
! 					      PY_ITERSEARCH_CONTAINS);
  	}
  }