Author: Squeaky <[email protected]>
Branch:
Changeset: r69685:4d70ac4b69b1
Date: 2014-03-04 18:47 +0100
http://bitbucket.org/pypy/pypy/changeset/4d70ac4b69b1/
Log: Implements SimpleRangeListStrategy for case range(n) where n is a
positive number.
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -94,3 +94,8 @@
.. branch: test-58c3d8552833
Fix for getarrayitem_gc_pure optimization
+
+.. branch: simple-range-strategy
+Implements SimpleRangeListStrategy for case range(n) where n is a positive
number.
+Makes some traces nicer by getting rid of multiplication for calculating loop
counter
+and propagates that n > 0 further to get rid of guards.
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -43,6 +43,10 @@
if length <= 0:
strategy = space.fromcache(EmptyListStrategy)
storage = strategy.erase(None)
+ elif start == 0 and step == 1:
+ strategy = space.fromcache(SimpleRangeListStrategy)
+ assert length > 0
+ storage = strategy.erase((length,))
else:
strategy = space.fromcache(RangeListStrategy)
storage = strategy.erase((start, step, length))
@@ -999,15 +1003,7 @@
self.sizehint = hint
-class RangeListStrategy(ListStrategy):
- """RangeListStrategy is used when a list is created using the range method.
- The storage is a tuple containing only three integers start, step and
- length and elements are calculated based on these values. On any operation
- destroying the range (inserting, appending non-ints) the strategy is
- switched to IntegerListStrategy."""
-
- _applevel_repr = "range"
-
+class BaseRangeListStrategy(ListStrategy):
def switch_to_integer_strategy(self, w_list):
items = self._getitems_range(w_list, False)
strategy = w_list.strategy = self.space.fromcache(IntegerListStrategy)
@@ -1022,10 +1018,6 @@
def init_from_list_w(self, w_list, list_w):
raise NotImplementedError
- erase, unerase = rerased.new_erasing_pair("range")
- erase = staticmethod(erase)
- unerase = staticmethod(unerase)
-
def clone(self, w_list):
storage = w_list.lstorage # lstorage is tuple, no need to clone
w_clone = W_ListObject.from_storage_and_strategy(self.space, storage,
@@ -1040,6 +1032,155 @@
w_other.strategy = self
w_other.lstorage = w_list.lstorage
+ def getitem(self, w_list, i):
+ return self.wrap(self._getitem_unwrapped(w_list, i))
+
+ def getitems_int(self, w_list):
+ return self._getitems_range(w_list, False)
+
+ def getitems_copy(self, w_list):
+ return self._getitems_range(w_list, True)
+
+ def getstorage_copy(self, w_list):
+ # tuple is immutable
+ return w_list.lstorage
+
+ @jit.dont_look_inside
+ def getitems_fixedsize(self, w_list):
+ return self._getitems_range_unroll(w_list, True)
+
+ def getitems_unroll(self, w_list):
+ return self._getitems_range_unroll(w_list, True)
+
+ def getslice(self, w_list, start, stop, step, length):
+ self.switch_to_integer_strategy(w_list)
+ return w_list.getslice(start, stop, step, length)
+
+ def append(self, w_list, w_item):
+ if type(w_item) is W_IntObject:
+ self.switch_to_integer_strategy(w_list)
+ else:
+ w_list.switch_to_object_strategy()
+ w_list.append(w_item)
+
+ def inplace_mul(self, w_list, times):
+ self.switch_to_integer_strategy(w_list)
+ w_list.inplace_mul(times)
+
+ def deleteslice(self, w_list, start, step, slicelength):
+ self.switch_to_integer_strategy(w_list)
+ w_list.deleteslice(start, step, slicelength)
+
+ def setitem(self, w_list, index, w_item):
+ self.switch_to_integer_strategy(w_list)
+ w_list.setitem(index, w_item)
+
+ def setslice(self, w_list, start, step, slicelength, sequence_w):
+ self.switch_to_integer_strategy(w_list)
+ w_list.setslice(start, step, slicelength, sequence_w)
+
+ def insert(self, w_list, index, w_item):
+ self.switch_to_integer_strategy(w_list)
+ w_list.insert(index, w_item)
+
+ def extend(self, w_list, w_any):
+ self.switch_to_integer_strategy(w_list)
+ w_list.extend(w_any)
+
+ def reverse(self, w_list):
+ self.switch_to_integer_strategy(w_list)
+ w_list.reverse()
+
+ def sort(self, w_list, reverse):
+ step = self.step(w_list)
+ if step > 0 and reverse or step < 0 and not reverse:
+ self.switch_to_integer_strategy(w_list)
+ w_list.sort(reverse)
+
+
+class SimpleRangeListStrategy(BaseRangeListStrategy):
+ """SimpleRangeListStrategy is used when a list is created using the range
+ method providing only positive length. The storage is a one element
tuple
+ with positive integer storing length."""
+
+ _applevel_repr = "simple_range"
+
+ erase, unerase = rerased.new_erasing_pair("simple_range")
+ erase = staticmethod(erase)
+ unerase = staticmethod(unerase)
+
+ def find(self, w_list, w_obj, startindex, stopindex):
+ if type(w_obj) is W_IntObject:
+ obj = self.unwrap(w_obj)
+ length = self.unerase(w_list.lstorage)[0]
+ if 0 <= obj < length and startindex <= obj < stopindex:
+ return obj
+ else:
+ raise ValueError
+ return ListStrategy.find(self, w_list, w_obj, startindex, stopindex)
+
+ def length(self, w_list):
+ return self.unerase(w_list.lstorage)[0]
+
+ def step(self, w_list):
+ return 1
+
+ def _getitem_unwrapped(self, w_list, i):
+ length = self.unerase(w_list.lstorage)[0]
+ assert length > 0
+ if 0 <= i < length:
+ return i
+ else:
+ raise IndexError
+
+ @specialize.arg(2)
+ def _getitems_range(self, w_list, wrap_items):
+ length = self.unerase(w_list.lstorage)[0]
+ if wrap_items:
+ r = [None] * length
+ else:
+ r = [0] * length
+ i = 0
+ while i < length:
+ if wrap_items:
+ r[i] = self.wrap(i)
+ else:
+ r[i] = i
+ i += 1
+
+ return r
+
+ _getitems_range_unroll = jit.unroll_safe(
+ func_with_new_name(_getitems_range, "_getitems_range_unroll"))
+
+ def pop_end(self, w_list):
+ new_length = self.unerase(w_list.lstorage)[0] - 1
+ w_result = self.wrap(new_length)
+ if new_length > 0:
+ w_list.lstorage = self.erase((new_length,))
+ else:
+ strategy = w_list.strategy =
self.space.fromcache(EmptyListStrategy)
+ w_list.lstorage = strategy.erase(None)
+ return w_result
+
+ def pop(self, w_list, index):
+ self.switch_to_integer_strategy(w_list)
+ return w_list.pop(index)
+
+
+class RangeListStrategy(BaseRangeListStrategy):
+ """RangeListStrategy is used when a list is created using the range method.
+ The storage is a tuple containing only three integers start, step and
+ length and elements are calculated based on these values. On any operation
+ destroying the range (inserting, appending non-ints) the strategy is
+ switched to IntegerListStrategy."""
+
+ _applevel_repr = "range"
+
+ erase, unerase = rerased.new_erasing_pair("range")
+ erase = staticmethod(erase)
+ unerase = staticmethod(unerase)
+
def find(self, w_list, w_obj, startindex, stopindex):
if type(w_obj) is W_IntObject:
obj = self.unwrap(w_obj)
@@ -1059,6 +1200,9 @@
def length(self, w_list):
return self.unerase(w_list.lstorage)[2]
+ def step(self, w_list):
+ return self.unerase(w_list.lstorage)[1]
+
def _getitem_unwrapped(self, w_list, i):
v = self.unerase(w_list.lstorage)
start = v[0]
@@ -1072,19 +1216,6 @@
raise IndexError
return start + i * step
- def getitems_int(self, w_list):
- return self._getitems_range(w_list, False)
-
- def getitem(self, w_list, i):
- return self.wrap(self._getitem_unwrapped(w_list, i))
-
- def getitems_copy(self, w_list):
- return self._getitems_range(w_list, True)
-
- def getstorage_copy(self, w_list):
- # tuple is unmutable
- return w_list.lstorage
-
@specialize.arg(2)
def _getitems_range(self, w_list, wrap_items):
l = self.unerase(w_list.lstorage)
@@ -1107,34 +1238,9 @@
return r
- @jit.dont_look_inside
- def getitems_fixedsize(self, w_list):
- return self._getitems_range_unroll(w_list, True)
-
- def getitems_unroll(self, w_list):
- return self._getitems_range_unroll(w_list, True)
_getitems_range_unroll = jit.unroll_safe(
func_with_new_name(_getitems_range, "_getitems_range_unroll"))
- def getslice(self, w_list, start, stop, step, length):
- self.switch_to_integer_strategy(w_list)
- return w_list.getslice(start, stop, step, length)
-
- def append(self, w_list, w_item):
- if type(w_item) is W_IntObject:
- self.switch_to_integer_strategy(w_list)
- else:
- w_list.switch_to_object_strategy()
- w_list.append(w_item)
-
- def inplace_mul(self, w_list, times):
- self.switch_to_integer_strategy(w_list)
- w_list.inplace_mul(times)
-
- def deleteslice(self, w_list, start, step, slicelength):
- self.switch_to_integer_strategy(w_list)
- w_list.deleteslice(start, step, slicelength)
-
def pop_end(self, w_list):
start, step, length = self.unerase(w_list.lstorage)
w_result = self.wrap(start + (length - 1) * step)
@@ -1158,32 +1264,6 @@
self.switch_to_integer_strategy(w_list)
return w_list.pop(index)
- def setitem(self, w_list, index, w_item):
- self.switch_to_integer_strategy(w_list)
- w_list.setitem(index, w_item)
-
- def setslice(self, w_list, start, step, slicelength, sequence_w):
- self.switch_to_integer_strategy(w_list)
- w_list.setslice(start, step, slicelength, sequence_w)
-
- def sort(self, w_list, reverse):
- step = self.unerase(w_list.lstorage)[1]
- if step > 0 and reverse or step < 0 and not reverse:
- self.switch_to_integer_strategy(w_list)
- w_list.sort(reverse)
-
- def insert(self, w_list, index, w_item):
- self.switch_to_integer_strategy(w_list)
- w_list.insert(index, w_item)
-
- def extend(self, w_list, w_any):
- self.switch_to_integer_strategy(w_list)
- w_list.extend(w_any)
-
- def reverse(self, w_list):
- self.switch_to_integer_strategy(w_list)
- w_list.reverse()
-
class AbstractUnwrappedStrategy(object):
@@ -1541,7 +1621,7 @@
_base_extend_from_list = _extend_from_list
def _extend_from_list(self, w_list, w_other):
- if w_other.strategy is self.space.fromcache(RangeListStrategy):
+ if isinstance(w_other.strategy, BaseRangeListStrategy):
l = self.unerase(w_list.lstorage)
other = w_other.getitems_int()
assert other is not None
diff --git a/pypy/objspace/std/test/test_liststrategies.py
b/pypy/objspace/std/test/test_liststrategies.py
--- a/pypy/objspace/std/test/test_liststrategies.py
+++ b/pypy/objspace/std/test/test_liststrategies.py
@@ -1,5 +1,8 @@
import sys
-from pypy.objspace.std.listobject import W_ListObject, EmptyListStrategy,
ObjectListStrategy, IntegerListStrategy, FloatListStrategy, BytesListStrategy,
RangeListStrategy, make_range_list, UnicodeListStrategy
+from pypy.objspace.std.listobject import (
+ W_ListObject, EmptyListStrategy, ObjectListStrategy, IntegerListStrategy,
+ FloatListStrategy, BytesListStrategy, RangeListStrategy,
+ SimpleRangeListStrategy, make_range_list, UnicodeListStrategy)
from pypy.objspace.std import listobject
from pypy.objspace.std.test.test_listobject import TestW_ListObject
@@ -18,7 +21,7 @@
UnicodeListStrategy)
assert isinstance(W_ListObject(space, [w(u'a'), w('b')]).strategy,
ObjectListStrategy) # mixed unicode and bytes
-
+
def test_empty_to_any(self):
space = self.space
w = space.wrap
@@ -183,7 +186,7 @@
def test_setslice(self):
space = self.space
w = space.wrap
-
+
l = W_ListObject(space, [])
assert isinstance(l.strategy, EmptyListStrategy)
l.setslice(0, 1, 2, W_ListObject(space, [w(1), w(2), w(3)]))
@@ -286,7 +289,7 @@
def test_empty_setslice_with_objectlist(self):
space = self.space
w = space.wrap
-
+
l = W_ListObject(space, [])
o = W_ListObject(space, [space.wrap(1), space.wrap("2"),
space.wrap(3)])
l.setslice(0, 1, o.length(), o)
@@ -347,6 +350,13 @@
empty = W_ListObject(space, [])
assert isinstance(empty.strategy, EmptyListStrategy)
+ r = make_range_list(space, 0, 1, 10)
+ empty.extend(r)
+ assert isinstance(empty.strategy, SimpleRangeListStrategy)
+ assert space.is_true(space.eq(empty.getitem(1), w(1)))
+
+ empty = W_ListObject(space, [])
+ assert isinstance(empty.strategy, EmptyListStrategy)
empty.extend(W_ListObject(space, [w(1), w(2), w(3)]))
assert isinstance(empty.strategy, IntegerListStrategy)
@@ -397,6 +407,72 @@
l.append(self.space.wrap(19))
assert isinstance(l.strategy, IntegerListStrategy)
+ def test_simplerangelist(self):
+ l = make_range_list(self.space, 0, 1, 10)
+ assert isinstance(l.strategy, SimpleRangeListStrategy)
+ v = l.pop(5)
+ assert self.space.eq_w(v, self.space.wrap(5))
+ assert isinstance(l.strategy, IntegerListStrategy)
+
+ l = make_range_list(self.space, 0, 1, 10)
+ assert isinstance(l.strategy, SimpleRangeListStrategy)
+ v = l.pop(0)
+ assert self.space.eq_w(v, self.space.wrap(0))
+ assert isinstance(l.strategy, IntegerListStrategy)
+
+ l = make_range_list(self.space, 0, 1, 10)
+ assert isinstance(l.strategy, SimpleRangeListStrategy)
+ v = l.pop_end()
+ assert self.space.eq_w(v, self.space.wrap(9))
+ assert isinstance(l.strategy, SimpleRangeListStrategy)
+ v = l.pop_end()
+ assert self.space.eq_w(v, self.space.wrap(8))
+ assert isinstance(l.strategy, SimpleRangeListStrategy)
+
+ l = make_range_list(self.space, 0, 1, 5)
+ assert isinstance(l.strategy, SimpleRangeListStrategy)
+ l.append(self.space.wrap("string"))
+ assert isinstance(l.strategy, ObjectListStrategy)
+
+ l = make_range_list(self.space, 0,1,5)
+ assert isinstance(l.strategy, SimpleRangeListStrategy)
+ l.append(self.space.wrap(19))
+ assert isinstance(l.strategy, IntegerListStrategy)
+
+ l = make_range_list(self.space, 0,1,5)
+ assert isinstance(l.strategy, SimpleRangeListStrategy)
+ assert l.find(self.space.wrap(0)) == 0
+ assert l.find(self.space.wrap(4)) == 4
+
+ try:
+ l.find(self.space.wrap(5))
+ except ValueError:
+ pass
+ else:
+ assert False, "Did not raise ValueError"
+
+ try:
+ l.find(self.space.wrap(0), 5, 6)
+ except ValueError:
+ pass
+ else:
+ assert False, "Did not raise ValueError"
+
+ assert l.length() == 5
+
+ l = make_range_list(self.space, 0, 1, 1)
+ assert self.space.eq_w(l.pop(0), self.space.wrap(0))
+
+ l = make_range_list(self.space, 0, 1, 10)
+ l.sort(False)
+ assert isinstance(l.strategy, SimpleRangeListStrategy)
+
+ assert self.space.eq_w(l.getitem(5), self.space.wrap(5))
+
+ l = make_range_list(self.space, 0, 1, 1)
+ assert self.space.eq_w(l.pop_end(), self.space.wrap(0))
+ assert isinstance(l.strategy, EmptyListStrategy)
+
def test_keep_range(self):
# simple list
l = make_range_list(self.space, 1,1,5)
diff --git a/pypy/objspace/std/test/test_rangeobject.py
b/pypy/objspace/std/test/test_rangeobject.py
--- a/pypy/objspace/std/test/test_rangeobject.py
+++ b/pypy/objspace/std/test/test_rangeobject.py
@@ -72,28 +72,43 @@
r.sort(key=lambda x: -x)
assert r == range(9, -1, -1)
def test_pop(self):
+ # RangeListStrategy
+ r = range(1, 10)
+ res = r.pop()
+ assert res == 9
+ assert self.not_forced(r)
+ assert repr(r) == repr(range(1, 9))
+ res = r.pop(0)
+ assert res == 1
+ assert self.not_forced(r)
+ assert repr(r) == repr(range(2, 9))
+ res = r.pop(len(r) - 1)
+ assert res == 8
+ assert self.not_forced(r)
+ assert repr(r) == repr(range(2, 8))
+ res = r.pop(2)
+ assert res == 4
+ assert not self.not_forced(r)
+ assert r == [2, 3, 5, 6, 7]
+ res = r.pop(2)
+ assert res == 5
+ assert not self.not_forced(r)
+ assert r == [2, 3, 6, 7]
+
+ # SimpleRangeListStrategy
r = range(10)
res = r.pop()
assert res == 9
assert self.not_forced(r)
- assert repr(r) == repr(range(9))
+ res = r.pop()
+ assert res == 8
+ assert repr(r) == repr(range(8))
+ assert self.not_forced(r)
res = r.pop(0)
assert res == 0
- assert self.not_forced(r)
- assert repr(r) == repr(range(1, 9))
- res = r.pop(len(r) - 1)
- assert res == 8
- assert self.not_forced(r)
- assert repr(r) == repr(range(1, 8))
- res = r.pop(2)
- assert res == 3
assert not self.not_forced(r)
- assert r == [1, 2, 4, 5, 6, 7]
- res = r.pop(2)
- assert res == 4
- assert not self.not_forced(r)
- assert r == [1, 2, 5, 6, 7]
-
+ assert r == [1, 2, 3, 4, 5, 6, 7]
+
def test_reduce(self):
it = iter(range(10))
assert it.next() == 0
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit