[pypy-svn] pypy default: (fijal, arigo)
arigo
commits-noreply at bitbucket.org
Thu Jan 20 10:25:53 CET 2011
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r40965:ee1f82a06937
Date: 2011-01-19 19:40 +0100
http://bitbucket.org/pypy/pypy/changeset/ee1f82a06937/
Log: (fijal, arigo)
Start refactoring range().
diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py
--- a/pypy/module/__builtin__/functional.py
+++ b/pypy/module/__builtin__/functional.py
@@ -11,22 +11,11 @@
from pypy.interpreter.argument import Arguments
from pypy.rlib.rarithmetic import r_uint, intmask
from pypy.rlib.objectmodel import specialize
-from pypy.module.__builtin__.app_functional import range as app_range
from inspect import getsource, getfile
from pypy.rlib.jit import unroll_safe
-"""
-Implementation of the common integer case of range. Instead of handling
-all other cases here, too, we fall back to the applevel implementation
-for non-integer arguments.
-Ideally this implementation could be saved, if we were able to
-specialize the geninterp generated code. But I guess having this
-hand-optimized is a good idea.
-Note the fun of using range inside range :-)
-"""
-
-def get_len_of_range(lo, hi, step):
+def get_len_of_range(space, lo, hi, step):
"""
Return number of items in range/xrange (lo, hi, step).
Raise ValueError if step == 0 and OverflowError if the true value is too
@@ -44,7 +33,8 @@
# hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough
# precision to compute the RHS exactly.
if step == 0:
- raise ValueError
+ raise OperationError(space.w_ValueError,
+ space.wrap("step argument must not be zero"))
elif step < 0:
lo, hi, step = hi, lo, -step
if lo < hi:
@@ -53,27 +43,48 @@
diff = uhi - ulo - 1
n = intmask(diff // r_uint(step) + 1)
if n < 0:
- raise OverflowError
+ raise OperationError(space.w_OverflowError,
+ space.wrap("result has too many items"))
else:
n = 0
return n
-def range(space, w_x, w_y=None, w_step=1):
+def range_int(space, w_x, w_y=NoneNotWrapped, w_step=1):
"""Return a list of integers in arithmetic position from start (defaults
to zero) to stop - 1 by step (defaults to 1). Use a negative step to
get a list in decending order."""
+ if w_y is None:
+ w_start = space.wrap(0)
+ w_stop = w_x
+ else:
+ w_start = w_x
+ w_stop = w_y
+
+ if space.is_true(space.isinstance(w_stop, space.w_float)):
+ raise OperationError(space.w_TypeError,
+ space.wrap("range() integer end argument expected, got float."))
+ if space.is_true(space.isinstance(w_start, space.w_float)):
+ raise OperationError(space.w_TypeError,
+ space.wrap("range() integer start argument expected, got float."))
+ if space.is_true(space.isinstance(w_step, space.w_float)):
+ raise OperationError(space.w_TypeError,
+ space.wrap("range() integer step argument expected, got float."))
+
+ w_start = space.int(w_start)
+ w_stop = space.int(w_stop)
+ w_step = space.int(w_step)
+
try:
- x = space.int_w(space.int(w_x))
- if space.is_w(w_y, space.w_None):
- start, stop = 0, x
- else:
- start, stop = x, space.int_w(space.int(w_y))
- step = space.int_w(space.int(w_step))
- howmany = get_len_of_range(start, stop, step)
- except (ValueError, OverflowError, OperationError):
- # save duplication by redirecting every error to applevel
- return range_fallback(space, w_x, w_y, w_step)
+ start = space.int_w(w_start)
+ stop = space.int_w(w_stop)
+ step = space.int_w(w_step)
+ except OperationError, e:
+ if not e.match(space, space.w_OverflowError):
+ raise
+ return range_with_longs(space, w_start, w_stop, w_step)
+
+ howmany = get_len_of_range(space, start, stop, step)
if space.config.objspace.std.withrangelist:
return range_withspecialized_implementation(space, start,
@@ -84,12 +95,8 @@
res_w[idx] = space.wrap(v)
v += step
return space.newlist(res_w)
-range_int = range
range_int.unwrap_spec = [ObjSpace, W_Root, W_Root, W_Root]
-del range # don't hide the builtin one
-range_fallback = applevel(getsource(app_range), getfile(app_range)
- ).interphook('range')
def range_withspecialized_implementation(space, start, step, howmany):
assert space.config.objspace.std.withrangelist
@@ -585,15 +592,7 @@
start, stop = 0, start
else:
stop = _toint(space, w_stop)
- try:
- howmany = get_len_of_range(start, stop, step)
- except ValueError:
- raise OperationError(space.w_ValueError,
- space.wrap("xrange() arg 3 must not be zero"))
- except OverflowError:
- raise OperationError(space.w_OverflowError,
- space.wrap("xrange() result has "
- "too many items"))
+ howmany = get_len_of_range(space, start, stop, step)
obj = space.allocate_instance(W_XRange, w_subtype)
W_XRange.__init__(obj, space, start, howmany, step)
return space.wrap(obj)
diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py
--- a/pypy/module/__builtin__/__init__.py
+++ b/pypy/module/__builtin__/__init__.py
@@ -30,9 +30,6 @@
'print' : 'app_io.print_',
'apply' : 'app_functional.apply',
- #'range' : 'app_functional.range',
- # redirected to functional.py, applevel version
- # is still needed and should stay where it is.
'sorted' : 'app_functional.sorted',
'vars' : 'app_inspect.vars',
'dir' : 'app_inspect.dir',
diff --git a/pypy/module/__builtin__/test/test_range.py b/pypy/module/__builtin__/test/test_range.py
--- a/pypy/module/__builtin__/test/test_range.py
+++ b/pypy/module/__builtin__/test/test_range.py
@@ -60,8 +60,12 @@
raises(ValueError, range, 1, 5, 0)
def test_range_float(self):
- "How CPython does it - UGLY."
- assert range(0.1, 2.0, 1.1) == [0, 1]
+ raises(TypeError, range, 0.1)
+ raises(TypeError, range, 0.1, 0)
+ raises(TypeError, range, 0, 0.1)
+ raises(TypeError, range, 0.1, 0, 0)
+ raises(TypeError, range, 0, 0.1, 0)
+ raises(TypeError, range, 0, 0, 0.1)
def test_range_wrong_type(self):
raises(TypeError, range, "42")
@@ -83,10 +87,7 @@
assert range(0, 2**100, -1) == []
a = long(10 * sys.maxint)
- b = long(100 * sys.maxint)
- c = long(50 * sys.maxint)
-
assert range(a, a+2) == [a, a+1]
assert range(a+2, a, -1L) == [a+2, a+1]
assert range(a+4, a, -2) == [a+4, a+2]
-
+ assert range(a, a*5, a) == [a, 2*a, 3*a, 4*a]
diff --git a/pypy/module/__builtin__/app_functional.py b/pypy/module/__builtin__/app_functional.py
--- a/pypy/module/__builtin__/app_functional.py
+++ b/pypy/module/__builtin__/app_functional.py
@@ -11,66 +11,8 @@
# ____________________________________________________________
-"""
-The following is a nice example of collaboration between
-interp-level and app-level.
-range is primarily implemented in functional.py for the integer case.
-On every error or different data types, it redirects to the applevel
-implementation below. functional.py uses this source via the inspect
-module and uses gateway.applevel. This is also an alternative to
-writing longer functions in strings.
-"""
-
-def range(x, y=None, step=1):
- """ returns a list of integers in arithmetic position from start (defaults
- to zero) to stop - 1 by step (defaults to 1). Use a negative step to
- get a list in decending order."""
-
-
- if y is None:
- start = 0
- stop = x
- else:
- start = x
- stop = y
-
- if not isinstance(start, (int, long)):
- raise TypeError('range() integer start argument expected, got %s' % type(start))
- if not isinstance(stop, (int, long)):
- raise TypeError('range() integer stop argument expected, got %s' % type(stop))
- if not isinstance(step, (int, long)):
- raise TypeError('range() integer step argument expected, got %s' % type(step))
-
- if step == 0:
- raise ValueError, 'range() arg 3 must not be zero'
-
- elif step > 0:
- if stop <= start: # no work for us
- return []
- howmany = (stop - start + step - 1)/step
-
- else: # step must be < 0, or we would have raised ValueError
- if stop >= start: # no work for us
- return []
- howmany = (start - stop - step - 1)/-step
-
- arr = [None] * howmany # this is to avoid using append.
-
- i = start
- n = 0
- while n < howmany:
- arr[n] = i
- i += step
- n += 1
-
- return arr
-
-# ____________________________________________________________
-
def sorted(lst, cmp=None, key=None, reverse=None):
"sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list"
sorted_lst = list(lst)
sorted_lst.sort(cmp, key, reverse)
return sorted_lst
-
-
More information about the Pypy-commit
mailing list