[Python-checkins] r58305 - in python/trunk: Doc/library/itertools.rst Lib/test/test_itertools.py Misc/NEWS Modules/itertoolsmodule.c

raymond.hettinger python-checkins at python.org
Thu Oct 4 02:20:28 CEST 2007


Author: raymond.hettinger
Date: Thu Oct  4 02:20:27 2007
New Revision: 58305

Modified:
   python/trunk/Doc/library/itertools.rst
   python/trunk/Lib/test/test_itertools.py
   python/trunk/Misc/NEWS
   python/trunk/Modules/itertoolsmodule.c
Log:
itertools.count() no longer limited to sys.maxint.

Modified: python/trunk/Doc/library/itertools.rst
==============================================================================
--- python/trunk/Doc/library/itertools.rst	(original)
+++ python/trunk/Doc/library/itertools.rst	Thu Oct  4 02:20:27 2007
@@ -79,19 +79,15 @@
 .. function:: count([n])
 
    Make an iterator that returns consecutive integers starting with *n*. If not
-   specified *n* defaults to zero.   Does not currently support python long
-   integers.  Often used as an argument to :func:`imap` to generate consecutive
-   data points. Also, used with :func:`izip` to add sequence numbers.  Equivalent
-   to::
+   specified *n* defaults to zero.   Often used as an argument to :func:`imap` to
+   generate consecutive data points. Also, used with :func:`izip` to add sequence
+   numbers.  Equivalent to::
 
       def count(n=0):
           while True:
               yield n
               n += 1
 
-   Note, :func:`count` does not check for overflow and will return negative numbers
-   after exceeding ``sys.maxint``.  This behavior may change in the future.
-
 
 .. function:: cycle(iterable)
 

Modified: python/trunk/Lib/test/test_itertools.py
==============================================================================
--- python/trunk/Lib/test/test_itertools.py	(original)
+++ python/trunk/Lib/test/test_itertools.py	Thu Oct  4 02:20:27 2007
@@ -52,9 +52,12 @@
         self.assertEqual(zip('abc',count()), [('a', 0), ('b', 1), ('c', 2)])
         self.assertEqual(zip('abc',count(3)), [('a', 3), ('b', 4), ('c', 5)])
         self.assertEqual(take(2, zip('abc',count(3))), [('a', 3), ('b', 4)])
+        self.assertEqual(take(2, zip('abc',count(-1))), [('a', -1), ('b', 0)])
+        self.assertEqual(take(2, zip('abc',count(-3))), [('a', -3), ('b', -2)])
         self.assertRaises(TypeError, count, 2, 3)
         self.assertRaises(TypeError, count, 'a')
-        self.assertRaises(OverflowError, list, islice(count(maxsize-5), 10))
+        self.assertEqual(list(islice(count(maxsize-5), 10)), range(maxsize-5, maxsize+5))
+        self.assertEqual(list(islice(count(-maxsize-5), 10)), range(-maxsize-5, -maxsize+5))
         c = count(3)
         self.assertEqual(repr(c), 'count(3)')
         c.next()
@@ -63,6 +66,8 @@
         self.assertEqual(repr(c), 'count(-9)')
         c.next()
         self.assertEqual(c.next(), -8)
+        for i in (-sys.maxint-5, -sys.maxint+5 ,-10, -1, 0, 10, sys.maxint-5, sys.maxint+5):
+            self.assertEqual(repr(count(i)), 'count(%r)' % i)
 
     def test_cycle(self):
         self.assertEqual(take(10, cycle('abc')), list('abcabcabca'))

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Thu Oct  4 02:20:27 2007
@@ -270,6 +270,9 @@
 Library
 -------
 
+- itertools.count() is no longer bounded to LONG_MAX.  Formerly, it raised
+  an OverflowError.  Now, automatically shifts from ints to longs.
+
 - Patch #1541463: optimize performance of cgi.FieldStorage operations.
 
 - Decimal is fully updated to the latest Decimal Specification (v1.66).

Modified: python/trunk/Modules/itertoolsmodule.c
==============================================================================
--- python/trunk/Modules/itertoolsmodule.c	(original)
+++ python/trunk/Modules/itertoolsmodule.c	Thu Oct  4 02:20:27 2007
@@ -2032,6 +2032,7 @@
 typedef struct {
 	PyObject_HEAD
 	Py_ssize_t cnt;
+	PyObject *long_cnt;	/* Arbitrarily large count when cnt >= PY_SSIZE_T_MAX */
 } countobject;
 
 static PyTypeObject count_type;
@@ -2041,37 +2042,97 @@
 {
 	countobject *lz;
 	Py_ssize_t cnt = 0;
+	PyObject *cnt_arg = NULL;
+	PyObject *long_cnt = NULL;
 
 	if (type == &count_type && !_PyArg_NoKeywords("count()", kwds))
 		return NULL;
 
-	if (!PyArg_ParseTuple(args, "|n:count", &cnt))
+	if (!PyArg_UnpackTuple(args, "count", 0, 1, &cnt_arg))
 		return NULL;
 
+	if (cnt_arg != NULL) {
+		cnt = PyInt_AsSsize_t(cnt_arg);
+		if (cnt == -1 && PyErr_Occurred()) {
+			PyErr_Clear();
+			if (!PyLong_Check(cnt_arg)) {
+				PyErr_SetString(PyExc_TypeError, "an integer is required");
+				return NULL;
+			}
+			long_cnt = cnt_arg;
+			Py_INCREF(long_cnt);
+			cnt = PY_SSIZE_T_MAX;
+		}
+	}
+
 	/* create countobject structure */
 	lz = (countobject *)PyObject_New(countobject, &count_type);
-	if (lz == NULL)
+	if (lz == NULL) {
+		Py_XDECREF(long_cnt);
 		return NULL;
+	}
 	lz->cnt = cnt;
+	lz->long_cnt = long_cnt;
 
 	return (PyObject *)lz;
 }
 
+static void
+count_dealloc(countobject *lz)
+{
+	Py_XDECREF(lz->long_cnt); 
+	PyObject_Del(lz);
+}
+
+static PyObject *
+count_nextlong(countobject *lz)
+{
+	static PyObject *one = NULL;
+	PyObject *cnt;
+	PyObject *stepped_up;
+
+	if (lz->long_cnt == NULL) {
+		lz->long_cnt = PyInt_FromSsize_t(PY_SSIZE_T_MAX);
+		if (lz->long_cnt == NULL)
+			return NULL;
+	}
+	if (one == NULL) {
+		one = PyInt_FromLong(1);
+		if (one == NULL)
+			return NULL;
+	}
+	cnt = lz->long_cnt;
+	assert(cnt != NULL);
+	stepped_up = PyNumber_Add(cnt, one);
+	if (stepped_up == NULL)
+		return NULL;
+	lz->long_cnt = stepped_up;
+	return cnt;
+}
+
 static PyObject *
 count_next(countobject *lz)
 {
-        if (lz->cnt == PY_SSIZE_T_MAX) {
-                PyErr_SetString(PyExc_OverflowError,
-                        "cannot count beyond PY_SSIZE_T_MAX");                
-                return NULL;         
-        }
+        if (lz->cnt == PY_SSIZE_T_MAX)
+		return count_nextlong(lz);
 	return PyInt_FromSsize_t(lz->cnt++);
 }
 
 static PyObject *
 count_repr(countobject *lz)
 {
-	return PyString_FromFormat("count(%zd)", lz->cnt);
+	PyObject *cnt_repr;
+	PyObject *result;
+
+        if (lz->cnt != PY_SSIZE_T_MAX)
+		return PyString_FromFormat("count(%zd)", lz->cnt);
+
+	cnt_repr = PyObject_Repr(lz->long_cnt);
+	if (cnt_repr == NULL)
+		return NULL;
+	result = PyString_FromFormat("count(%s)", PyString_AS_STRING(cnt_repr));
+	Py_DECREF(cnt_repr);
+	return result;
 }
 
 PyDoc_STRVAR(count_doc,
@@ -2086,7 +2147,7 @@
 	sizeof(countobject),		/* tp_basicsize */
 	0,				/* tp_itemsize */
 	/* methods */
-	(destructor)PyObject_Del,	/* tp_dealloc */
+	(destructor)count_dealloc,	/* tp_dealloc */
 	0,				/* tp_print */
 	0,				/* tp_getattr */
 	0,				/* tp_setattr */


More information about the Python-checkins mailing list