Author: Maciej Fijalkowski <[email protected]>
Branch: missing-ndarray-attributes
Changeset: r57396:66cd721062be
Date: 2012-09-19 17:41 +0200
http://bitbucket.org/pypy/pypy/changeset/66cd721062be/
Log: few hacks to make TimSort reusable on stuff that's not really lists
diff --git a/pypy/rlib/listsort.py b/pypy/rlib/listsort.py
--- a/pypy/rlib/listsort.py
+++ b/pypy/rlib/listsort.py
@@ -7,10 +7,22 @@
## ------------------------------------------------------------------------
## Adapted from CPython, original code and algorithms by Tim Peters
-def make_timsort_class():
+def list_getitem(list, item):
+ return list[item]
- class TimSort:
+def list_setitem(list, item, value):
+ list[item] = value
+def list_length(list):
+ return len(list)
+
+def list_getitem_slice(list, start, stop):
+ return list[start:stop]
+
+def make_timsort_class(getitem=list_getitem, setitem=list_setitem,
+ length=list_length, getitem_slice=list_getitem_slice):
+
+ class TimSort(object):
"""TimSort(list).sort()
Sorts the list in-place, using the overridable method lt() for
comparison.
@@ -19,9 +31,12 @@
def __init__(self, list, listlength=None):
self.list = list
if listlength is None:
- listlength = len(list)
+ listlength = length(list)
self.listlength = listlength
+ def setitem(self, item, val):
+ setitem(self.list, item, val)
+
def lt(self, a, b):
return a < b
@@ -236,7 +251,7 @@
# We use a finally block to ensure that the elements remaining in
# the copy "a" are reinserted back into self.list in all cases.
try:
- self.list[dest] = b.popleft()
+ self.setitem(dest, b.popleft())
dest += 1
if a.len == 1 or b.len == 0:
return
@@ -249,7 +264,7 @@
# appears to win consistently.
while True:
if self.lt(b.list[b.base], a.list[a.base]):
- self.list[dest] = b.popleft()
+ self.setitem(dest, b.popleft())
dest += 1
if b.len == 0:
return
@@ -258,7 +273,7 @@
if bcount >= min_gallop:
break
else:
- self.list[dest] = a.popleft()
+ self.setitem(dest, a.popleft())
dest += 1
if a.len == 1:
return
@@ -280,7 +295,7 @@
acount = self.gallop(b.list[b.base], a, hint=0,
rightmost=True)
for p in xrange(a.base, a.base + acount):
- self.list[dest] = a.list[p]
+ self.setitem(dest, a.getitem(p))
dest += 1
a.advance(acount)
# a.len==0 is impossible now if the comparison
@@ -289,7 +304,7 @@
if a.len <= 1:
return
- self.list[dest] = b.popleft()
+ self.setitem(dest, b.popleft())
dest += 1
if b.len == 0:
return
@@ -297,13 +312,13 @@
bcount = self.gallop(a.list[a.base], b, hint=0,
rightmost=False)
for p in xrange(b.base, b.base + bcount):
- self.list[dest] = b.list[p]
+ self.setitem(dest, b.getitem(p))
dest += 1
b.advance(bcount)
if b.len == 0:
return
- self.list[dest] = a.popleft()
+ self.setitem(dest, a.popleft())
dest += 1
if a.len == 1:
return
@@ -319,10 +334,10 @@
# the remaining elements of b before the remaining elements of
a.
assert a.len >= 0 and b.len >= 0
for p in xrange(b.base, b.base + b.len):
- self.list[dest] = b.list[p]
+ self.setitem(dest, b.getitem(p))
dest += 1
for p in xrange(a.base, a.base + a.len):
- self.list[dest] = a.list[p]
+ self.setitem(dest, a.getitem(p))
dest += 1
# Same as merge_lo(), but should have a.len >= b.len.
@@ -340,7 +355,7 @@
# the copy "b" are reinserted back into self.list in all cases.
try:
dest -= 1
- self.list[dest] = a.popright()
+ self.setitem(dest, a.popright())
if a.len == 0 or b.len == 1:
return
@@ -355,7 +370,7 @@
nextb = b.list[b.base + b.len - 1]
if self.lt(nextb, nexta):
dest -= 1
- self.list[dest] = nexta
+ self.setitem(dest, nexta)
a.len -= 1
if a.len == 0:
return
@@ -365,7 +380,7 @@
break
else:
dest -= 1
- self.list[dest] = nextb
+ self.setitem(dest, nextb)
b.len -= 1
if b.len == 1:
return
@@ -389,13 +404,13 @@
acount = a.len - k
for p in xrange(a.base + a.len - 1, a.base + k - 1,
-1):
dest -= 1
- self.list[dest] = a.list[p]
+ self.setitem(dest, a.getitem(p))
a.len -= acount
if a.len == 0:
return
dest -= 1
- self.list[dest] = b.popright()
+ self.setitem(dest, b.popright())
if b.len == 1:
return
@@ -404,7 +419,7 @@
bcount = b.len - k
for p in xrange(b.base + b.len - 1, b.base + k - 1,
-1):
dest -= 1
- self.list[dest] = b.list[p]
+ self.setitem(dest, b.getitem(p))
b.len -= bcount
# b.len==0 is impossible now if the comparison
# function is consistent, but we can't assume
@@ -413,7 +428,7 @@
return
dest -= 1
- self.list[dest] = a.popright()
+ self.setitem(dest, a.popright())
if a.len == 0:
return
@@ -429,10 +444,10 @@
assert a.len >= 0 and b.len >= 0
for p in xrange(a.base + a.len - 1, a.base - 1, -1):
dest -= 1
- self.list[dest] = a.list[p]
+ self.setitem(dest, a.getitem(p))
for p in xrange(b.base + b.len - 1, b.base - 1, -1):
dest -= 1
- self.list[dest] = b.list[p]
+ self.setitem(dest, b.getitem(p))
# Merge the two runs at stack indices i and i+1.
@@ -565,21 +580,24 @@
start = self.base
stop = self.base + self.len
assert 0 <= start <= stop # annotator hint
- return ListSlice(self.list[start:stop], 0, self.len)
+ return ListSlice(getitem_slice(self.list, start, stop), 0,
self.len)
def advance(self, n):
self.base += n
self.len -= n
+ def getitem(self, item):
+ return getitem(self.list, item)
+
def popleft(self):
- result = self.list[self.base]
+ result = getitem(self.list, self.base)
self.base += 1
self.len -= 1
return result
def popright(self):
self.len -= 1
- return self.list[self.base + self.len]
+ return getitem(self.list, self.base + self.len)
def reverse(self):
"Reverse the slice in-place."
@@ -587,7 +605,10 @@
lo = self.base
hi = lo + self.len - 1
while lo < hi:
- list[lo], list[hi] = list[hi], list[lo]
+ list_hi = getitem(list, hi)
+ list_lo = getitem(list, lo)
+ setitem(list, lo, list_hi)
+ setitem(list, hi, list_lo)
lo += 1
hi -= 1
return TimSort
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit