[pypy-svn] r17743 - pypy/dist/pypy/module/__builtin__
tismer at codespeak.net
tismer at codespeak.net
Wed Sep 21 20:14:21 CEST 2005
Author: tismer
Date: Wed Sep 21 20:14:19 2005
New Revision: 17743
Added:
pypy/dist/pypy/module/__builtin__/functional.py (contents, props changed)
Modified:
pypy/dist/pypy/module/__builtin__/__init__.py
pypy/dist/pypy/module/__builtin__/app_functional.py
Log:
added an interplevel implementation of range.
The original function will stay in app_functional;
it is used for non-integer and all exception cases.
The speed effect on pystone is just tremendous,
although I believe that this would be almost
achievable by specialization of geninterp output.
Not easily, of course, so I think this is worth the small effort.
Modified: pypy/dist/pypy/module/__builtin__/__init__.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/__init__.py (original)
+++ pypy/dist/pypy/module/__builtin__/__init__.py Wed Sep 21 20:14:19 2005
@@ -22,7 +22,9 @@
'filter' : 'app_functional.filter',
'zip' : 'app_functional.zip',
'reduce' : 'app_functional.reduce',
- 'range' : 'app_functional.range',
+ #'range' : 'app_functional.range',
+ # redirected to functional.py, applevel version
+ # is still needed and should stay where it is.
'min' : 'app_functional.min',
'max' : 'app_functional.max',
'enumerate' : 'app_functional.enumerate',
@@ -107,6 +109,8 @@
'__import__' : 'importing.importhook',
+ 'range' : 'functional.range_int',
+
# float->string helper
'_formatd' : 'special._formatd'
}
Modified: pypy/dist/pypy/module/__builtin__/app_functional.py
==============================================================================
--- pypy/dist/pypy/module/__builtin__/app_functional.py (original)
+++ pypy/dist/pypy/module/__builtin__/app_functional.py Wed Sep 21 20:14:19 2005
@@ -140,6 +140,16 @@
# ____________________________________________________________
+"""
+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
@@ -147,11 +157,11 @@
if y is None:
- start = 0
- stop = x
+ start = 0
+ stop = x
else:
- start = x
- stop = y
+ start = x
+ stop = y
if not isinstance(start, (int, long)):
raise TypeError('range() integer start argument expected, got %s' % type(start))
@@ -302,7 +312,7 @@
if not isinstance(index, int):
raise TypeError, "sequence index must be integer"
len = self.len
- if index<0:
+ if index < 0:
index += len
if 0 <= index < len:
return self.start + index * self.step
Added: pypy/dist/pypy/module/__builtin__/functional.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/__builtin__/functional.py Wed Sep 21 20:14:19 2005
@@ -0,0 +1,94 @@
+"""
+Interp-level definition of frequently used functionals.
+
+Candidates implemented
+
+ range yes
+ zip no
+ min no
+ max no
+ enumerate no
+ xrange no
+
+"""
+
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.gateway import ObjSpace, W_Root, NoneNotWrapped, applevel
+from pypy.rpython.rarithmetic import r_uint, intmask
+from pypy.module.__builtin__.app_functional import range as app_range
+from inspect import getsource, getfile
+
+"""
+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):
+ """
+ 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.
+ """
+
+ # 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.
+
+ # slight modification: we raise on everything bad and also adjust args
+ if step == 0:
+ raise ValueError
+ elif step < 0:
+ lo, hi, step = hi, lo, -step
+ if lo < hi:
+ uhi = r_uint(hi)
+ ulo = r_uint(lo)
+ diff = uhi - ulo - 1
+ n = intmask(diff // r_uint(step) + 1)
+ if n < 0:
+ raise OverflowError
+ else:
+ n = 0
+ return n
+
+def range(space, w_x, w_y=None, w_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."""
+
+ try:
+ # save duplication by redirecting every error to applevel
+ x = space.int_w(w_x)
+ if w_y is space.w_None:
+ start, stop = 0, x
+ else:
+ start, stop = x, space.int_w(w_y)
+ step = space.int_w(w_step)
+ howmany = get_len_of_range(start, stop, step)
+ except (OperationError, ValueError, OverflowError):
+ return range_fallback(space, w_x, w_y, w_step)
+
+ res_w = [None] * howmany
+ v = start
+ for idx in range(howmany):
+ 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')
More information about the Pypy-commit
mailing list