]> granicus.if.org Git - python/commitdiff
Skip Montanaro's patch, SF 559833, exposing xrange type in builtins.
authorRaymond Hettinger <python@rcn.com>
Wed, 5 Jun 2002 23:12:45 +0000 (23:12 +0000)
committerRaymond Hettinger <python@rcn.com>
Wed, 5 Jun 2002 23:12:45 +0000 (23:12 +0000)
Also, added more regression tests to cover the new type and test its
conformity with range().

Lib/test/test_b2.py
Lib/types.py
Objects/rangeobject.c
Python/bltinmodule.c

index 459fd6b851a9737865da89e6d44f2168f21bf89e..a8bc22adb8ef489575ec11526fbeea412046f6b3 100644 (file)
@@ -295,6 +295,11 @@ if tuple(xrange(10)) != tuple(range(10)): raise TestFailed, 'xrange(10)'
 if tuple(xrange(5,10)) != tuple(range(5,10)): raise TestFailed, 'xrange(5,10)'
 if tuple(xrange(0,10,2)) != tuple(range(0,10,2)):
     raise TestFailed, 'xrange(0,10,2)'
+x = xrange(10); a = iter(x); b = iter(a)  # test clearing of SF bug 564601
+if id(x) == id(a): raise TestFailed, "xrange doesn't have a separate iterator"
+if id(a) != id(b): raise TestFailed, "xrange iterator not behaving like range"
+if type(x) != xrange: raise TestFailed, "xrange type not exposed"  # SF 559833
+if list(x) != list(x): raise TestFailed, "xrange should be restartable"
 
 print 'zip'
 a = (1, 2, 3)
index 0d5174314cbad61da512879c2aeaebb7c4fc0fe4..da0e59748781afa4572e4f10a326a49bc9bcd6a2 100644 (file)
@@ -62,7 +62,7 @@ BuiltinMethodType = type([].append)     # Same as BuiltinFunctionType
 
 ModuleType = type(sys)
 FileType = file
-XRangeType = type(xrange(0))
+XRangeType = xrange
 
 try:
     raise TypeError
index 002f94a40ca87e71d3ec28a9e690053ac58f5b9b..0ac46872097a566c0a381ba81c710b55ed31143b 100644 (file)
@@ -47,6 +47,76 @@ PyRange_New(long start, long len, long step, int reps)
        return (PyObject *) obj;
 }
 
+/* Return number of items in range/xrange (lo, hi, step).  step > 0
+ * required.  Return a value < 0 if & only if the true value is too
+ * large to fit in a signed long.
+ */
+static long
+get_len_of_range(long lo, long hi, long step)
+{
+       /* -------------------------------------------------------------
+       If lo >= hi, the range is empty.
+       Else if n values are in the range, the last one is
+       lo + (n-1)*step, which must be <= hi-1.  Rearranging,
+       n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
+       the proper value.  Since lo < hi in this case, hi-lo-1 >= 0, so
+       the RHS is non-negative and so truncation is the same as the
+       floor.  Letting M be the largest positive long, the worst case
+       for the RHS numerator is hi=M, lo=-M-1, and then
+       hi-lo-1 = M-(-M-1)-1 = 2*M.  Therefore unsigned long has enough
+       precision to compute the RHS exactly.
+       ---------------------------------------------------------------*/
+       long n = 0;
+       if (lo < hi) {
+               unsigned long uhi = (unsigned long)hi;
+               unsigned long ulo = (unsigned long)lo;
+               unsigned long diff = uhi - ulo - 1;
+               n = (long)(diff / (unsigned long)step + 1);
+       }
+       return n;
+}
+
+static PyObject *
+range_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+{
+       long ilow = 0, ihigh = 0, istep = 1;
+       long n;
+
+       if (PyTuple_Size(args) <= 1) {
+               if (!PyArg_ParseTuple(args,
+                               "l;xrange() requires 1-3 int arguments",
+                               &ihigh))
+                       return NULL;
+       }
+       else {
+               if (!PyArg_ParseTuple(args,
+                               "ll|l;xrange() requires 1-3 int arguments",
+                               &ilow, &ihigh, &istep))
+                       return NULL;
+       }
+       if (istep == 0) {
+               PyErr_SetString(PyExc_ValueError, "xrange() arg 3 must not be zero");
+               return NULL;
+       }
+       if (istep > 0)
+               n = get_len_of_range(ilow, ihigh, istep);
+       else
+               n = get_len_of_range(ihigh, ilow, -istep);
+       if (n < 0) {
+               PyErr_SetString(PyExc_OverflowError,
+                               "xrange() result has too many items");
+               return NULL;
+       }
+       return PyRange_New(ilow, n, istep, 1);
+}
+
+static char range_doc[] =
+"xrange([start,] stop[, step]) -> xrange object\n\
+\n\
+Like range(), but instead of returning a list, returns an object that\n\
+generates the numbers in the range on demand.  This is slightly slower\n\
+than range() but more memory efficient.";
+
 static PyObject *
 range_item(rangeobject *r, int i)
 {
@@ -118,12 +188,24 @@ PyTypeObject PyRange_Type = {
        0,                              /* tp_setattro */
        0,                              /* tp_as_buffer */
        Py_TPFLAGS_DEFAULT,             /* tp_flags */
-       0,                              /* tp_doc */
+       range_doc,                      /* tp_doc */
        0,                              /* tp_traverse */
        0,                              /* tp_clear */
        0,                              /* tp_richcompare */
        0,                              /* tp_weaklistoffset */
-       (getiterfunc)range_iter,        /* tp_iter */   
+       (getiterfunc)range_iter,        /* tp_iter */
+       0,                              /* tp_iternext */
+       0,                              /* tp_methods */        
+       0,                              /* tp_members */
+       0,                              /* tp_getset */
+       0,                              /* tp_base */
+       0,                              /* tp_dict */
+       0,                              /* tp_descr_get */
+       0,                              /* tp_descr_set */
+       0,                              /* tp_dictoffset */
+       0,                              /* tp_init */
+       0,                              /* tp_alloc */
+       range_new,                      /* tp_new */
 };
 
 /*********************** Xrange Iterator **************************/
index fba1b49e469454c30c4112110b99e91dd6f8dea7..5aa6bc70ea57e4e9dd78cc3a6dc3c9936ec7c200 100644 (file)
@@ -1364,48 +1364,6 @@ For example, range(4) returns [0, 1, 2, 3].  The end point is omitted!\n\
 These are exactly the valid indices for a list of 4 elements.";
 
 
-static PyObject *
-builtin_xrange(PyObject *self, PyObject *args)
-{
-       long ilow = 0, ihigh = 0, istep = 1;
-       long n;
-
-       if (PyTuple_Size(args) <= 1) {
-               if (!PyArg_ParseTuple(args,
-                               "l;xrange() requires 1-3 int arguments",
-                               &ihigh))
-                       return NULL;
-       }
-       else {
-               if (!PyArg_ParseTuple(args,
-                               "ll|l;xrange() requires 1-3 int arguments",
-                               &ilow, &ihigh, &istep))
-                       return NULL;
-       }
-       if (istep == 0) {
-               PyErr_SetString(PyExc_ValueError, "xrange() arg 3 must not be zero");
-               return NULL;
-       }
-       if (istep > 0)
-               n = get_len_of_range(ilow, ihigh, istep);
-       else
-               n = get_len_of_range(ihigh, ilow, -istep);
-       if (n < 0) {
-               PyErr_SetString(PyExc_OverflowError,
-                               "xrange() result has too many items");
-               return NULL;
-       }
-       return PyRange_New(ilow, n, istep, 1);
-}
-
-static char xrange_doc[] =
-"xrange([start,] stop[, step]) -> xrange object\n\
-\n\
-Like range(), but instead of returning a list, returns an object that\n\
-generates the numbers in the range on demand.  This is slightly slower\n\
-than range() but more memory efficient.";
-
-
 static PyObject *
 builtin_raw_input(PyObject *self, PyObject *args)
 {
@@ -1860,7 +1818,6 @@ static PyMethodDef builtin_methods[] = {
        {"unichr",      builtin_unichr,     METH_VARARGS, unichr_doc},
 #endif
        {"vars",        builtin_vars,       METH_VARARGS, vars_doc},
-       {"xrange",      builtin_xrange,     METH_VARARGS, xrange_doc},
        {"zip",         builtin_zip,        METH_VARARGS, zip_doc},
        {NULL,          NULL},
 };
@@ -1909,6 +1866,7 @@ _PyBuiltin_Init(void)
        SETBUILTIN("super",             &PySuper_Type);
        SETBUILTIN("tuple",             &PyTuple_Type);
        SETBUILTIN("type",              &PyType_Type);
+       SETBUILTIN("xrange",            &PyRange_Type);
 
        /* Note that open() is just an alias of file(). */
        SETBUILTIN("open",              &PyFile_Type);