Author: Maciej Fijalkowski <fij...@gmail.com> Branch: Changeset: r48818:5a19f9787d6b Date: 2011-11-06 11:14 +0100 http://bitbucket.org/pypy/pypy/changeset/5a19f9787d6b/
Log: merge default diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -201,7 +201,7 @@ RegrTest('test_difflib.py'), RegrTest('test_dircache.py', core=True), RegrTest('test_dis.py'), - RegrTest('test_distutils.py'), + RegrTest('test_distutils.py', skip=True), RegrTest('test_dl.py', skip=True), RegrTest('test_doctest.py', usemodules="thread"), RegrTest('test_doctest2.py'), diff --git a/lib-python/modified-2.7/ctypes/test/test_simplesubclasses.py b/lib-python/modified-2.7/ctypes/test/test_simplesubclasses.py --- a/lib-python/modified-2.7/ctypes/test/test_simplesubclasses.py +++ b/lib-python/modified-2.7/ctypes/test/test_simplesubclasses.py @@ -1,6 +1,5 @@ import unittest from ctypes import * -from ctypes.test import xfail class MyInt(c_int): def __cmp__(self, other): @@ -27,7 +26,6 @@ self.assertEqual(None, cb()) - @xfail def test_int_callback(self): args = [] def func(arg): diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py --- a/lib_pypy/_ctypes/structure.py +++ b/lib_pypy/_ctypes/structure.py @@ -17,7 +17,7 @@ if len(f) == 3: if (not hasattr(tp, '_type_') or not isinstance(tp._type_, str) - or tp._type_ not in "iIhHbBlL"): + or tp._type_ not in "iIhHbBlLqQ"): #XXX: are those all types? # we just dont get the type name # in the interp levle thrown TypeError diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py --- a/pypy/jit/metainterp/optimizeopt/optimizer.py +++ b/pypy/jit/metainterp/optimizeopt/optimizer.py @@ -247,7 +247,6 @@ CONST_1 = ConstInt(1) CVAL_ZERO = ConstantValue(CONST_0) CVAL_ZERO_FLOAT = ConstantValue(Const._new(0.0)) -CVAL_UNINITIALIZED_ZERO = ConstantValue(CONST_0) llhelper.CVAL_NULLREF = ConstantValue(llhelper.CONST_NULL) oohelper.CVAL_NULLREF = ConstantValue(oohelper.CONST_NULL) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4123,6 +4123,38 @@ """ self.optimize_strunicode_loop(ops, expected) + def test_str_concat_constant_lengths(self): + ops = """ + [i0] + p0 = newstr(1) + strsetitem(p0, 0, i0) + p1 = newstr(0) + p2 = call(0, p0, p1, descr=strconcatdescr) + i1 = call(0, p2, p0, descr=strequaldescr) + finish(i1) + """ + expected = """ + [i0] + finish(1) + """ + self.optimize_strunicode_loop(ops, expected) + + def test_str_concat_constant_lengths_2(self): + ops = """ + [i0] + p0 = newstr(0) + p1 = newstr(1) + strsetitem(p1, 0, i0) + p2 = call(0, p0, p1, descr=strconcatdescr) + i1 = call(0, p2, p1, descr=strequaldescr) + finish(i1) + """ + expected = """ + [i0] + finish(1) + """ + self.optimize_strunicode_loop(ops, expected) + def test_str_slice_1(self): ops = """ [p1, i1, i2] @@ -4883,6 +4915,27 @@ def test_plain_virtual_string_copy_content(self): ops = """ + [i1] + p0 = newstr(6) + copystrcontent(s"hello!", p0, 0, 0, 6) + p1 = call(0, p0, s"abc123", descr=strconcatdescr) + i0 = strgetitem(p1, i1) + finish(i0) + """ + expected = """ + [i1] + p0 = newstr(6) + copystrcontent(s"hello!", p0, 0, 0, 6) + p1 = newstr(12) + copystrcontent(p0, p1, 0, 0, 6) + copystrcontent(s"abc123", p1, 0, 6, 6) + i0 = strgetitem(p1, i1) + finish(i0) + """ + self.optimize_strunicode_loop(ops, expected) + + def test_plain_virtual_string_copy_content_2(self): + ops = """ [] p0 = newstr(6) copystrcontent(s"hello!", p0, 0, 0, 6) @@ -4894,10 +4947,7 @@ [] p0 = newstr(6) copystrcontent(s"hello!", p0, 0, 0, 6) - p1 = newstr(12) - copystrcontent(p0, p1, 0, 0, 6) - copystrcontent(s"abc123", p1, 0, 6, 6) - i0 = strgetitem(p1, 0) + i0 = strgetitem(p0, 0) finish(i0) """ self.optimize_strunicode_loop(ops, expected) diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -2168,13 +2168,13 @@ ops = """ [p0, i0, p1, i1, i2] setfield_gc(p0, i1, descr=valuedescr) - copystrcontent(p0, i0, p1, i1, i2) + copystrcontent(p0, p1, i0, i1, i2) escape() jump(p0, i0, p1, i1, i2) """ expected = """ [p0, i0, p1, i1, i2] - copystrcontent(p0, i0, p1, i1, i2) + copystrcontent(p0, p1, i0, i1, i2) setfield_gc(p0, i1, descr=valuedescr) escape() jump(p0, i0, p1, i1, i2) @@ -7407,7 +7407,7 @@ expected = """ [p22, p18, i1, i2] call(i2, descr=nonwritedescr) - setfield_gc(p22, i1, descr=valuedescr) + setfield_gc(p22, i1, descr=valuedescr) jump(p22, p18, i1, i1) """ self.optimize_loop(ops, expected, preamble, expected_short=short) @@ -7434,7 +7434,7 @@ def test_cache_setarrayitem_across_loop_boundaries(self): ops = """ [p1] - p2 = getarrayitem_gc(p1, 3, descr=arraydescr) + p2 = getarrayitem_gc(p1, 3, descr=arraydescr) guard_nonnull_class(p2, ConstClass(node_vtable)) [] call(p2, descr=nonwritedescr) p3 = new_with_vtable(ConstClass(node_vtable)) diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py --- a/pypy/jit/metainterp/optimizeopt/vstring.py +++ b/pypy/jit/metainterp/optimizeopt/vstring.py @@ -1,6 +1,6 @@ from pypy.jit.codewriter.effectinfo import EffectInfo from pypy.jit.metainterp.history import (BoxInt, Const, ConstInt, ConstPtr, - get_const_ptr_for_string, get_const_ptr_for_unicode) + get_const_ptr_for_string, get_const_ptr_for_unicode, BoxPtr, REF, INT) from pypy.jit.metainterp.optimizeopt import optimizer, virtualize from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1, llhelper from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method @@ -106,7 +106,12 @@ if not we_are_translated(): op.name = 'FORCE' optforce.emit_operation(op) - self.string_copy_parts(optforce, box, CONST_0, self.mode) + self.initialize_forced_string(optforce, box, CONST_0, self.mode) + + def initialize_forced_string(self, string_optimizer, targetbox, + offsetbox, mode): + return self.string_copy_parts(string_optimizer, targetbox, + offsetbox, mode) class VStringPlainValue(VAbstractStringValue): @@ -114,11 +119,20 @@ _lengthbox = None # cache only def setup(self, size): - self._chars = [optimizer.CVAL_UNINITIALIZED_ZERO] * size + # in this list, None means: "it's probably uninitialized so far, + # but maybe it was actually filled." So to handle this case, + # strgetitem cannot be virtual-ized and must be done as a residual + # operation. By contrast, any non-None value means: we know it + # is initialized to this value; strsetitem() there makes no sense. + # Also, as long as self.is_virtual(), then we know that no-one else + # could have written to the string, so we know that in this case + # "None" corresponds to "really uninitialized". + self._chars = [None] * size def setup_slice(self, longerlist, start, stop): assert 0 <= start <= stop <= len(longerlist) self._chars = longerlist[start:stop] + # slice the 'longerlist', which may also contain Nones def getstrlen(self, _, mode): if self._lengthbox is None: @@ -126,42 +140,66 @@ return self._lengthbox def getitem(self, index): - return self._chars[index] + return self._chars[index] # may return None! def setitem(self, index, charvalue): assert isinstance(charvalue, optimizer.OptValue) + assert self._chars[index] is None, ( + "setitem() on an already-initialized location") self._chars[index] = charvalue + def is_completely_initialized(self): + for c in self._chars: + if c is None: + return False + return True + @specialize.arg(1) def get_constant_string_spec(self, mode): for c in self._chars: - if c is optimizer.CVAL_UNINITIALIZED_ZERO or not c.is_constant(): + if c is None or not c.is_constant(): return None return mode.emptystr.join([mode.chr(c.box.getint()) for c in self._chars]) def string_copy_parts(self, string_optimizer, targetbox, offsetbox, mode): - if not self.is_virtual() and targetbox is not self.box: - lengthbox = self.getstrlen(string_optimizer, mode) - srcbox = self.force_box(string_optimizer) - return copy_str_content(string_optimizer, srcbox, targetbox, - CONST_0, offsetbox, lengthbox, mode) + if not self.is_virtual() and not self.is_completely_initialized(): + return VAbstractStringValue.string_copy_parts( + self, string_optimizer, targetbox, offsetbox, mode) + else: + return self.initialize_forced_string(string_optimizer, targetbox, + offsetbox, mode) + + def initialize_forced_string(self, string_optimizer, targetbox, + offsetbox, mode): for i in range(len(self._chars)): - charbox = self._chars[i].force_box(string_optimizer) - if not (isinstance(charbox, Const) and charbox.same_constant(CONST_0)): - string_optimizer.emit_operation(ResOperation(mode.STRSETITEM, [targetbox, - offsetbox, - charbox], - None)) + assert isinstance(targetbox, BoxPtr) # ConstPtr never makes sense + charvalue = self.getitem(i) + if charvalue is not None: + charbox = charvalue.force_box(string_optimizer) + if not (isinstance(charbox, Const) and + charbox.same_constant(CONST_0)): + op = ResOperation(mode.STRSETITEM, [targetbox, + offsetbox, + charbox], + None) + string_optimizer.emit_operation(op) offsetbox = _int_add(string_optimizer, offsetbox, CONST_1) return offsetbox def get_args_for_fail(self, modifier): if self.box is None and not modifier.already_seen_virtual(self.keybox): - charboxes = [value.get_key_box() for value in self._chars] + charboxes = [] + for value in self._chars: + if value is not None: + box = value.get_key_box() + else: + box = None + charboxes.append(box) modifier.register_virtual_fields(self.keybox, charboxes) for value in self._chars: - value.get_args_for_fail(modifier) + if value is not None: + value.get_args_for_fail(modifier) def _make_virtual(self, modifier): return modifier.make_vstrplain(self.mode is mode_unicode) @@ -169,6 +207,7 @@ class VStringConcatValue(VAbstractStringValue): """The concatenation of two other strings.""" + _attrs_ = ('left', 'right', 'lengthbox') lengthbox = None # or the computed length @@ -277,6 +316,7 @@ for i in range(lengthbox.value): charbox = _strgetitem(string_optimizer, srcbox, srcoffsetbox, mode) srcoffsetbox = _int_add(string_optimizer, srcoffsetbox, CONST_1) + assert isinstance(targetbox, BoxPtr) # ConstPtr never makes sense string_optimizer.emit_operation(ResOperation(mode.STRSETITEM, [targetbox, offsetbox, charbox], @@ -287,6 +327,7 @@ nextoffsetbox = _int_add(string_optimizer, offsetbox, lengthbox) else: nextoffsetbox = None + assert isinstance(targetbox, BoxPtr) # ConstPtr never makes sense op = ResOperation(mode.COPYSTRCONTENT, [srcbox, targetbox, srcoffsetbox, offsetbox, lengthbox], None) @@ -373,6 +414,7 @@ def optimize_STRSETITEM(self, op): value = self.getvalue(op.getarg(0)) + assert not value.is_constant() # strsetitem(ConstPtr) never makes sense if value.is_virtual() and isinstance(value, VStringPlainValue): indexbox = self.get_constant_box(op.getarg(1)) if indexbox is not None: @@ -406,11 +448,20 @@ # if isinstance(value, VStringPlainValue): # even if no longer virtual if vindex.is_constant(): - res = value.getitem(vindex.box.getint()) - # If it is uninitialized we can't return it, it was set by a - # COPYSTRCONTENT, not a STRSETITEM - if res is not optimizer.CVAL_UNINITIALIZED_ZERO: - return res + result = value.getitem(vindex.box.getint()) + if result is not None: + return result + # + if isinstance(value, VStringConcatValue) and vindex.is_constant(): + len1box = value.left.getstrlen(self, mode) + if isinstance(len1box, ConstInt): + index = vindex.box.getint() + len1 = len1box.getint() + if index < len1: + return self.strgetitem(value.left, vindex, mode) + else: + vindex = optimizer.ConstantValue(ConstInt(index - len1)) + return self.strgetitem(value.right, vindex, mode) # resbox = _strgetitem(self, value.force_box(self), vindex.force_box(self), mode) return self.getvalue(resbox) @@ -432,6 +483,11 @@ def _optimize_COPYSTRCONTENT(self, op, mode): # args: src dst srcstart dststart length + assert op.getarg(0).type == REF + assert op.getarg(1).type == REF + assert op.getarg(2).type == INT + assert op.getarg(3).type == INT + assert op.getarg(4).type == INT src = self.getvalue(op.getarg(0)) dst = self.getvalue(op.getarg(1)) srcstart = self.getvalue(op.getarg(2)) @@ -503,19 +559,12 @@ vstart = self.getvalue(op.getarg(2)) vstop = self.getvalue(op.getarg(3)) # - if (isinstance(vstr, VStringPlainValue) and vstart.is_constant() - and vstop.is_constant()): - # slicing with constant bounds of a VStringPlainValue, if any of - # the characters is unitialized we don't do this special slice, we - # do the regular copy contents. - for i in range(vstart.box.getint(), vstop.box.getint()): - if vstr.getitem(i) is optimizer.CVAL_UNINITIALIZED_ZERO: - break - else: - value = self.make_vstring_plain(op.result, op, mode) - value.setup_slice(vstr._chars, vstart.box.getint(), - vstop.box.getint()) - return True + #if (isinstance(vstr, VStringPlainValue) and vstart.is_constant() + # and vstop.is_constant()): + # value = self.make_vstring_plain(op.result, op, mode) + # value.setup_slice(vstr._chars, vstart.box.getint(), + # vstop.box.getint()) + # return True # vstr.ensure_nonnull() lengthbox = _int_sub(self, vstop.force_box(self), diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py --- a/pypy/jit/metainterp/resume.py +++ b/pypy/jit/metainterp/resume.py @@ -126,6 +126,7 @@ UNASSIGNED = tag(-1<<13, TAGBOX) UNASSIGNEDVIRTUAL = tag(-1<<13, TAGVIRTUAL) NULLREF = tag(-1, TAGCONST) +UNINITIALIZED = tag(-2, TAGCONST) # used for uninitialized string characters class ResumeDataLoopMemo(object): @@ -439,6 +440,8 @@ self.storage.rd_pendingfields = rd_pendingfields def _gettagged(self, box): + if box is None: + return UNINITIALIZED if isinstance(box, Const): return self.memo.getconst(box) else: @@ -572,7 +575,9 @@ string = decoder.allocate_string(length) decoder.virtuals_cache[index] = string for i in range(length): - decoder.string_setitem(string, i, self.fieldnums[i]) + charnum = self.fieldnums[i] + if not tagged_eq(charnum, UNINITIALIZED): + decoder.string_setitem(string, i, charnum) return string def debug_prints(self): @@ -625,7 +630,9 @@ string = decoder.allocate_unicode(length) decoder.virtuals_cache[index] = string for i in range(length): - decoder.unicode_setitem(string, i, self.fieldnums[i]) + charnum = self.fieldnums[i] + if not tagged_eq(charnum, UNINITIALIZED): + decoder.unicode_setitem(string, i, charnum) return string def debug_prints(self): diff --git a/pypy/jit/metainterp/test/test_virtualstate.py b/pypy/jit/metainterp/test/test_virtualstate.py --- a/pypy/jit/metainterp/test/test_virtualstate.py +++ b/pypy/jit/metainterp/test/test_virtualstate.py @@ -847,7 +847,8 @@ i5 = arraylen_gc(p2, descr=arraydescr) i6 = int_ge(i5, 1) guard_true(i6) [] - jump(p0, p1, p2) + p3 = getarrayitem_gc(p2, 0, descr=arraydescr) + jump(p0, p1, p3, p2) """ self.optimize_bridge(loop, bridge, expected, p0=self.myptr) 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 @@ -312,11 +312,10 @@ class W_XRange(Wrappable): - def __init__(self, space, start, stop, step): + def __init__(self, space, start, len, step): self.space = space self.start = start - self.stop = stop - self.len = get_len_of_range(space, start, stop, step) + self.len = len self.step = step def descr_new(space, w_subtype, w_start, w_stop=None, w_step=1): @@ -326,8 +325,9 @@ start, stop = 0, start else: stop = _toint(space, w_stop) + howmany = get_len_of_range(space, start, stop, step) obj = space.allocate_instance(W_XRange, w_subtype) - W_XRange.__init__(obj, space, start, stop, step) + W_XRange.__init__(obj, space, start, howmany, step) return space.wrap(obj) def descr_repr(self): @@ -357,12 +357,12 @@ def descr_iter(self): return self.space.wrap(W_XRangeIterator(self.space, self.start, - self.stop, self.step)) + self.len, self.step)) def descr_reversed(self): lastitem = self.start + (self.len-1) * self.step return self.space.wrap(W_XRangeIterator(self.space, lastitem, - self.start - 1, -self.step)) + self.len, -self.step)) def descr_reduce(self): space = self.space @@ -389,24 +389,25 @@ ) class W_XRangeIterator(Wrappable): - def __init__(self, space, start, stop, step): + def __init__(self, space, current, remaining, step): self.space = space - self.current = start - self.stop = stop + self.current = current + self.remaining = remaining self.step = step def descr_iter(self): return self.space.wrap(self) def descr_next(self): - if (self.step > 0 and self.current < self.stop) or (self.step < 0 and self.current > self.stop): + if self.remaining > 0: item = self.current self.current = item + self.step + self.remaining -= 1 return self.space.wrap(item) raise OperationError(self.space.w_StopIteration, self.space.w_None) - #def descr_len(self): - # return self.space.wrap(self.remaining) + def descr_len(self): + return self.space.wrap(self.remaining) def descr_reduce(self): from pypy.interpreter.mixedmodule import MixedModule @@ -417,7 +418,7 @@ w = space.wrap nt = space.newtuple - tup = [w(self.current), w(self.stop), w(self.step)] + tup = [w(self.current), w(self.remaining), w(self.step)] return nt([new_inst, nt(tup)]) W_XRangeIterator.typedef = TypeDef("rangeiterator", diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py --- a/pypy/module/_file/interp_file.py +++ b/pypy/module/_file/interp_file.py @@ -206,24 +206,28 @@ @unwrap_spec(size=int) def direct_readlines(self, size=0): stream = self.getstream() - # NB. this implementation is very inefficient for unbuffered - # streams, but ok if stream.readline() is efficient. + # this is implemented as: .read().split('\n') + # except that it keeps the \n in the resulting strings if size <= 0: - result = [] - while True: - line = stream.readline() - if not line: - break - result.append(line) - size -= len(line) + data = stream.readall() else: - result = [] - while size > 0: - line = stream.readline() - if not line: - break - result.append(line) - size -= len(line) + data = stream.read(size) + result = [] + splitfrom = 0 + for i in range(len(data)): + if data[i] == '\n': + result.append(data[splitfrom : i + 1]) + splitfrom = i + 1 + # + if splitfrom < len(data): + # there is a partial line at the end. If size > 0, it is likely + # to be because the 'read(size)' returned data up to the middle + # of a line. In that case, use 'readline()' to read until the + # end of the current line. + data = data[splitfrom:] + if size > 0: + data += stream.readline() + result.append(data) return result @unwrap_spec(offset=r_longlong, whence=int) diff --git a/pypy/module/_pickle_support/maker.py b/pypy/module/_pickle_support/maker.py --- a/pypy/module/_pickle_support/maker.py +++ b/pypy/module/_pickle_support/maker.py @@ -66,10 +66,10 @@ new_generator.running = running return space.wrap(new_generator) -@unwrap_spec(current=int, stop=int, step=int) -def xrangeiter_new(space, current, stop, step): +@unwrap_spec(current=int, remaining=int, step=int) +def xrangeiter_new(space, current, remaining, step): from pypy.module.__builtin__.functional import W_XRangeIterator - new_iter = W_XRangeIterator(space, current, stop, step) + new_iter = W_XRangeIterator(space, current, remaining, step) return space.wrap(new_iter) @unwrap_spec(identifier=str) diff --git a/pypy/objspace/std/boolobject.py b/pypy/objspace/std/boolobject.py --- a/pypy/objspace/std/boolobject.py +++ b/pypy/objspace/std/boolobject.py @@ -27,11 +27,7 @@ def uint_w(w_self, space): intval = int(w_self.boolval) - if intval < 0: - raise OperationError(space.w_ValueError, - space.wrap("cannot convert negative integer to unsigned")) - else: - return r_uint(intval) + return r_uint(intval) def bigint_w(w_self, space): return rbigint.fromint(int(w_self.boolval)) diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py --- a/pypy/objspace/std/bytearrayobject.py +++ b/pypy/objspace/std/bytearrayobject.py @@ -283,17 +283,9 @@ return space.wrap(''.join(w_bytearray.data)) def _convert_idx_params(space, w_self, w_start, w_stop): - start = slicetype.eval_slice_index(space, w_start) - stop = slicetype.eval_slice_index(space, w_stop) length = len(w_self.data) - if start < 0: - start += length - if start < 0: - start = 0 - if stop < 0: - stop += length - if stop < 0: - stop = 0 + start, stop = slicetype.unwrap_start_stop( + space, length, w_start, w_stop, False) return start, stop, length def str_count__Bytearray_Int_ANY_ANY(space, w_bytearray, w_char, w_start, w_stop): 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 @@ -419,8 +419,8 @@ # needs to be safe against eq_w() mutating the w_list behind our back items = w_list.wrappeditems size = len(items) - i = slicetype.adapt_bound(space, size, w_start) - stop = slicetype.adapt_bound(space, size, w_stop) + i, stop = slicetype.unwrap_start_stop( + space, size, w_start, w_stop, True) while i < stop and i < len(items): if space.eq_w(items[i], w_any): return space.wrap(i) diff --git a/pypy/objspace/std/ropeobject.py b/pypy/objspace/std/ropeobject.py --- a/pypy/objspace/std/ropeobject.py +++ b/pypy/objspace/std/ropeobject.py @@ -357,16 +357,8 @@ self = w_self._node sub = w_sub._node - if space.is_w(w_start, space.w_None): - w_start = space.wrap(0) - if space.is_w(w_end, space.w_None): - w_end = space.len(w_self) - if upper_bound: - start = slicetype.adapt_bound(space, self.length(), w_start) - end = slicetype.adapt_bound(space, self.length(), w_end) - else: - start = slicetype.adapt_lower_bound(space, self.length(), w_start) - end = slicetype.adapt_lower_bound(space, self.length(), w_end) + start, end = slicetype.unwrap_start_stop( + space, self.length(), w_start, w_end, upper_bound) return (self, sub, start, end) _convert_idx_params._annspecialcase_ = 'specialize:arg(5)' diff --git a/pypy/objspace/std/sliceobject.py b/pypy/objspace/std/sliceobject.py --- a/pypy/objspace/std/sliceobject.py +++ b/pypy/objspace/std/sliceobject.py @@ -4,7 +4,7 @@ from pypy.interpreter import gateway from pypy.objspace.std.model import registerimplementation, W_Object from pypy.objspace.std.register_all import register_all -from pypy.objspace.std.slicetype import eval_slice_index +from pypy.objspace.std.slicetype import _eval_slice_index class W_SliceObject(W_Object): from pypy.objspace.std.slicetype import slice_typedef as typedef @@ -25,7 +25,7 @@ if space.is_w(w_slice.w_step, space.w_None): step = 1 else: - step = eval_slice_index(space, w_slice.w_step) + step = _eval_slice_index(space, w_slice.w_step) if step == 0: raise OperationError(space.w_ValueError, space.wrap("slice step cannot be zero")) @@ -35,7 +35,7 @@ else: start = 0 else: - start = eval_slice_index(space, w_slice.w_start) + start = _eval_slice_index(space, w_slice.w_start) if start < 0: start += length if start < 0: @@ -54,7 +54,7 @@ else: stop = length else: - stop = eval_slice_index(space, w_slice.w_stop) + stop = _eval_slice_index(space, w_slice.w_stop) if stop < 0: stop += length if stop < 0: diff --git a/pypy/objspace/std/slicetype.py b/pypy/objspace/std/slicetype.py --- a/pypy/objspace/std/slicetype.py +++ b/pypy/objspace/std/slicetype.py @@ -3,6 +3,7 @@ from pypy.objspace.std.stdtypedef import StdTypeDef, SMM from pypy.objspace.std.register_all import register_all from pypy.interpreter.error import OperationError +from pypy.rlib.objectmodel import specialize # indices multimehtod slice_indices = SMM('indices', 2, @@ -14,7 +15,9 @@ ' normal slices.') # utility functions -def eval_slice_index(space, w_int): +def _eval_slice_index(space, w_int): + # note that it is the *callers* responsibility to check for w_None + # otherwise you can get funny error messages try: return space.getindex_w(w_int, None) # clamp if long integer too large except OperationError, err: @@ -25,7 +28,7 @@ "None or have an __index__ method")) def adapt_lower_bound(space, size, w_index): - index = eval_slice_index(space, w_index) + index = _eval_slice_index(space, w_index) if index < 0: index = index + size if index < 0: @@ -34,16 +37,29 @@ return index def adapt_bound(space, size, w_index): - index = eval_slice_index(space, w_index) - if index < 0: - index = index + size - if index < 0: - index = 0 + index = adapt_lower_bound(space, size, w_index) if index > size: index = size assert index >= 0 return index +@specialize.arg(4) +def unwrap_start_stop(space, size, w_start, w_end, upper_bound=False): + if space.is_w(w_start, space.w_None): + start = 0 + elif upper_bound: + start = adapt_bound(space, size, w_start) + else: + start = adapt_lower_bound(space, size, w_start) + + if space.is_w(w_end, space.w_None): + end = size + elif upper_bound: + end = adapt_bound(space, size, w_end) + else: + end = adapt_lower_bound(space, size, w_end) + return start, end + register_all(vars(), globals()) # ____________________________________________________________ diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py --- a/pypy/objspace/std/smalltupleobject.py +++ b/pypy/objspace/std/smalltupleobject.py @@ -68,10 +68,10 @@ raise IndexError def eq(self, space, w_other): - if self.length() != w_other.length(): + if n != w_other.length(): return space.w_False for i in iter_n: - item1 = self.getitem(i) + item1 = getattr(self,'w_value%s' % i) item2 = w_other.getitem(i) if not space.eq_w(item1, item2): return space.w_False @@ -80,9 +80,9 @@ def hash(self, space): mult = 1000003 x = 0x345678 - z = self.length() + z = n for i in iter_n: - w_item = self.getitem(i) + w_item = getattr(self, 'w_value%s' % i) y = space.int_w(space.hash(w_item)) x = (x ^ y) * mult z -= 1 diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py --- a/pypy/objspace/std/stringobject.py +++ b/pypy/objspace/std/stringobject.py @@ -4,7 +4,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter import gateway from pypy.rlib.rarithmetic import ovfcheck -from pypy.rlib.objectmodel import we_are_translated, compute_hash +from pypy.rlib.objectmodel import we_are_translated, compute_hash, specialize from pypy.objspace.std.inttype import wrapint from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice from pypy.objspace.std import slicetype, newformat @@ -47,6 +47,7 @@ W_StringObject.PREBUILT = [W_StringObject(chr(i)) for i in range(256)] del i +@specialize.arg(2) def _is_generic(space, w_self, fun): v = w_self._value if len(v) == 0: @@ -56,14 +57,13 @@ return space.newbool(fun(c)) else: return _is_generic_loop(space, v, fun) -_is_generic._annspecialcase_ = "specialize:arg(2)" +@specialize.arg(2) def _is_generic_loop(space, v, fun): for idx in range(len(v)): if not fun(v[idx]): return space.w_False return space.w_True -_is_generic_loop._annspecialcase_ = "specialize:arg(2)" def _upper(ch): if ch.islower(): @@ -420,22 +420,14 @@ return space.wrap(u_self) -def _convert_idx_params(space, w_self, w_sub, w_start, w_end, upper_bound=False): +@specialize.arg(4) +def _convert_idx_params(space, w_self, w_start, w_end, upper_bound=False): self = w_self._value - sub = w_sub._value + lenself = len(self) - if space.is_w(w_start, space.w_None): - w_start = space.wrap(0) - if space.is_w(w_end, space.w_None): - w_end = space.len(w_self) - if upper_bound: - start = slicetype.adapt_bound(space, len(self), w_start) - end = slicetype.adapt_bound(space, len(self), w_end) - else: - start = slicetype.adapt_lower_bound(space, len(self), w_start) - end = slicetype.adapt_lower_bound(space, len(self), w_end) - return (self, sub, start, end) -_convert_idx_params._annspecialcase_ = 'specialize:arg(5)' + start, end = slicetype.unwrap_start_stop( + space, lenself, w_start, w_end, upper_bound=upper_bound) + return (self, start, end) def contains__String_String(space, w_self, w_sub): self = w_self._value @@ -443,13 +435,13 @@ return space.newbool(self.find(sub) >= 0) def str_find__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, sub, start, end) = _convert_idx_params(space, w_self, w_sub, w_start, w_end) - res = self.find(sub, start, end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + res = self.find(w_sub._value, start, end) return space.wrap(res) def str_rfind__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, sub, start, end) = _convert_idx_params(space, w_self, w_sub, w_start, w_end) - res = self.rfind(sub, start, end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + res = self.rfind(w_sub._value, start, end) return space.wrap(res) def str_partition__String_String(space, w_self, w_sub): @@ -483,8 +475,8 @@ def str_index__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, sub, start, end) = _convert_idx_params(space, w_self, w_sub, w_start, w_end) - res = self.find(sub, start, end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + res = self.find(w_sub._value, start, end) if res < 0: raise OperationError(space.w_ValueError, space.wrap("substring not found in string.index")) @@ -493,8 +485,8 @@ def str_rindex__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end): - (self, sub, start, end) = _convert_idx_params(space, w_self, w_sub, w_start, w_end) - res = self.rfind(sub, start, end) + (self, start, end) = _convert_idx_params(space, w_self, w_start, w_end) + res = self.rfind(w_sub._value, start, end) if res < 0: raise OperationError(space.w_ValueError, space.wrap("substring not found in string.rindex")) @@ -636,20 +628,17 @@ return wrapstr(space, u_centered) def str_count__String_String_ANY_ANY(space, w_self, w_arg, w_start, w_end): - u_self, u_arg, u_start, u_end = _convert_idx_params(space, w_self, w_arg, - w_start, w_end) - return wrapint(space, u_self.count(u_arg, u_start, u_end)) + u_self, u_start, u_end = _convert_idx_params(space, w_self, w_start, w_end) + return wrapint(space, u_self.count(w_arg._value, u_start, u_end)) def str_endswith__String_String_ANY_ANY(space, w_self, w_suffix, w_start, w_end): - (u_self, suffix, start, end) = _convert_idx_params(space, w_self, - w_suffix, w_start, - w_end, True) - return space.newbool(stringendswith(u_self, suffix, start, end)) + (u_self, start, end) = _convert_idx_params(space, w_self, w_start, + w_end, True) + return space.newbool(stringendswith(u_self, w_suffix._value, start, end)) def str_endswith__String_Tuple_ANY_ANY(space, w_self, w_suffixes, w_start, w_end): - (u_self, _, start, end) = _convert_idx_params(space, w_self, - space.wrap(''), w_start, - w_end, True) + (u_self, start, end) = _convert_idx_params(space, w_self, w_start, + w_end, True) for w_suffix in space.fixedview(w_suffixes): if space.isinstance_w(w_suffix, space.w_unicode): w_u = space.call_function(space.w_unicode, w_self) @@ -661,14 +650,13 @@ return space.w_False def str_startswith__String_String_ANY_ANY(space, w_self, w_prefix, w_start, w_end): - (u_self, prefix, start, end) = _convert_idx_params(space, w_self, - w_prefix, w_start, - w_end, True) - return space.newbool(stringstartswith(u_self, prefix, start, end)) + (u_self, start, end) = _convert_idx_params(space, w_self, w_start, + w_end, True) + return space.newbool(stringstartswith(u_self, w_prefix._value, start, end)) def str_startswith__String_Tuple_ANY_ANY(space, w_self, w_prefixes, w_start, w_end): - (u_self, _, start, end) = _convert_idx_params(space, w_self, space.wrap(''), - w_start, w_end, True) + (u_self, start, end) = _convert_idx_params(space, w_self, + w_start, w_end, True) for w_prefix in space.fixedview(w_prefixes): if space.isinstance_w(w_prefix, space.w_unicode): w_u = space.call_function(space.w_unicode, w_self) diff --git a/pypy/objspace/std/strsliceobject.py b/pypy/objspace/std/strsliceobject.py --- a/pypy/objspace/std/strsliceobject.py +++ b/pypy/objspace/std/strsliceobject.py @@ -60,8 +60,8 @@ def _convert_idx_params(space, w_self, w_sub, w_start, w_end): length = w_self.stop - w_self.start sub = w_sub._value - start = slicetype.adapt_bound(space, length, w_start) - end = slicetype.adapt_bound(space, length, w_end) + start, end = slicetype.unwrap_start_stop( + space, length, w_start, w_end, True) assert start >= 0 assert end >= 0 diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py --- a/pypy/objspace/std/test/test_listobject.py +++ b/pypy/objspace/std/test/test_listobject.py @@ -2,11 +2,10 @@ from pypy.objspace.std.listobject import W_ListObject from pypy.interpreter.error import OperationError -from pypy.conftest import gettestobjspace +from pypy.conftest import gettestobjspace, option class TestW_ListObject(object): - def test_is_true(self): w = self.space.wrap w_list = W_ListObject([]) @@ -343,6 +342,13 @@ class AppTestW_ListObject(object): + def setup_class(cls): + import sys + on_cpython = (option.runappdirect and + not hasattr(sys, 'pypy_translation_info')) + + cls.w_on_cpython = cls.space.wrap(on_cpython) + def test_call_list(self): assert list('') == [] assert list('abc') == ['a', 'b', 'c'] @@ -616,6 +622,14 @@ assert c.index(0) == 0 raises(ValueError, c.index, 3) + def test_index_cpython_bug(self): + if self.on_cpython: + skip("cpython has a bug here") + c = list('hello world') + assert c.index('l', None, None) == 2 + assert c.index('l', 3, None) == 3 + assert c.index('l', None, 4) == 2 + def test_ass_slice(self): l = range(6) l[1:3] = 'abc' diff --git a/pypy/objspace/std/test/test_sliceobject.py b/pypy/objspace/std/test/test_sliceobject.py --- a/pypy/objspace/std/test/test_sliceobject.py +++ b/pypy/objspace/std/test/test_sliceobject.py @@ -42,6 +42,23 @@ getslice(length, mystart, mystop)) + def test_indexes4(self): + space = self.space + w = space.wrap + + def getslice(length, start, stop, step): + return [i for i in range(0, length, step) if start <= i < stop] + + for step in [-5, -4, -3, -2, -1, 1, 2, 3, 4, 5, None]: + for length in range(5): + for start in range(-2*length-2, 2*length+3) + [None]: + for stop in range(-2*length-2, 2*length+3) + [None]: + sl = space.newslice(w(start), w(stop), w(step)) + mystart, mystop, mystep, slicelength = sl.indices4(space, length) + assert len(range(length)[start:stop:step]) == slicelength + assert slice(start, stop, step).indices(length) == ( + mystart, mystop, mystep) + class AppTest_SliceObject: def test_new(self): def cmp_slice(sl1, sl2): diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py --- a/pypy/objspace/std/tupleobject.py +++ b/pypy/objspace/std/tupleobject.py @@ -167,17 +167,8 @@ return space.wrap(count) def tuple_index__Tuple_ANY_ANY_ANY(space, w_tuple, w_obj, w_start, w_stop): - start = slicetype.eval_slice_index(space, w_start) - stop = slicetype.eval_slice_index(space, w_stop) length = len(w_tuple.wrappeditems) - if start < 0: - start += length - if start < 0: - start = 0 - if stop < 0: - stop += length - if stop < 0: - stop = 0 + start, stop = slicetype.unwrap_start_stop(space, length, w_start, w_stop) for i in range(start, min(stop, length)): w_item = w_tuple.wrappeditems[i] if space.eq_w(w_item, w_obj): diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py --- a/pypy/objspace/std/unicodeobject.py +++ b/pypy/objspace/std/unicodeobject.py @@ -10,7 +10,7 @@ from pypy.objspace.std import slicetype, newformat from pypy.objspace.std.tupleobject import W_TupleObject from pypy.rlib.rarithmetic import intmask, ovfcheck -from pypy.rlib.objectmodel import compute_hash +from pypy.rlib.objectmodel import compute_hash, specialize from pypy.rlib.rstring import UnicodeBuilder from pypy.rlib.runicode import unicode_encode_unicode_escape from pypy.module.unicodedata import unicodedb @@ -475,42 +475,29 @@ index = length return index -def _convert_idx_params(space, w_self, w_sub, w_start, w_end, upper_bound=False): - assert isinstance(w_sub, W_UnicodeObject) +@specialize.arg(4) +def _convert_idx_params(space, w_self, w_start, w_end, upper_bound=False): self = w_self._value - sub = w_sub._value - - if space.is_w(w_start, space.w_None): - w_start = space.wrap(0) - if space.is_w(w_end, space.w_None): - w_end = space.len(w_self) - - if upper_bound: - start = slicetype.adapt_bound(space, len(self), w_start) - end = slicetype.adapt_bound(space, len(self), w_end) - else: - start = slicetype.adapt_lower_bound(space, len(self), w_start) - end = slicetype.adapt_lower_bound(space, len(self), w_end) - return (self, sub, start, end) -_convert_idx_params._annspecialcase_ = 'specialize:arg(5)' + start, end = slicetype.unwrap_start_stop( + space, len(self), w_start, w_end, upper_bound) + return (self, start, end) def unicode_endswith__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): - self, substr, start, end = _convert_idx_params(space, w_self, w_substr, + self, start, end = _convert_idx_params(space, w_self, w_start, w_end, True) - return space.newbool(stringendswith(self, substr, start, end)) + return space.newbool(stringendswith(self, w_substr._value, start, end)) def unicode_startswith__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): - self, substr, start, end = _convert_idx_params(space, w_self, w_substr, - w_start, w_end, True) + self, start, end = _convert_idx_params(space, w_self, w_start, w_end, True) # XXX this stuff can be waaay better for ootypebased backends if # we re-use more of our rpython machinery (ie implement startswith # with additional parameters as rpython) - return space.newbool(stringstartswith(self, substr, start, end)) + return space.newbool(stringstartswith(self, w_substr._value, start, end)) def unicode_startswith__Unicode_Tuple_ANY_ANY(space, w_unistr, w_prefixes, w_start, w_end): - unistr, _, start, end = _convert_idx_params(space, w_unistr, space.wrap(u''), - w_start, w_end, True) + unistr, start, end = _convert_idx_params(space, w_unistr, + w_start, w_end, True) for w_prefix in space.fixedview(w_prefixes): prefix = space.unicode_w(w_prefix) if stringstartswith(unistr, prefix, start, end): @@ -519,7 +506,7 @@ def unicode_endswith__Unicode_Tuple_ANY_ANY(space, w_unistr, w_suffixes, w_start, w_end): - unistr, _, start, end = _convert_idx_params(space, w_unistr, space.wrap(u''), + unistr, start, end = _convert_idx_params(space, w_unistr, w_start, w_end, True) for w_suffix in space.fixedview(w_suffixes): suffix = space.unicode_w(w_suffix) @@ -625,37 +612,32 @@ return space.newlist(lines) def unicode_find__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): - self, substr, start, end = _convert_idx_params(space, w_self, w_substr, - w_start, w_end) - return space.wrap(self.find(substr, start, end)) + self, start, end = _convert_idx_params(space, w_self, w_start, w_end) + return space.wrap(self.find(w_substr._value, start, end)) def unicode_rfind__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): - self, substr, start, end = _convert_idx_params(space, w_self, w_substr, - w_start, w_end) - return space.wrap(self.rfind(substr, start, end)) + self, start, end = _convert_idx_params(space, w_self, w_start, w_end) + return space.wrap(self.rfind(w_substr._value, start, end)) def unicode_index__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): - self, substr, start, end = _convert_idx_params(space, w_self, w_substr, - w_start, w_end) - index = self.find(substr, start, end) + self, start, end = _convert_idx_params(space, w_self, w_start, w_end) + index = self.find(w_substr._value, start, end) if index < 0: raise OperationError(space.w_ValueError, space.wrap('substring not found')) return space.wrap(index) def unicode_rindex__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): - self, substr, start, end = _convert_idx_params(space, w_self, w_substr, - w_start, w_end) - index = self.rfind(substr, start, end) + self, start, end = _convert_idx_params(space, w_self, w_start, w_end) + index = self.rfind(w_substr._value, start, end) if index < 0: raise OperationError(space.w_ValueError, space.wrap('substring not found')) return space.wrap(index) def unicode_count__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end): - self, substr, start, end = _convert_idx_params(space, w_self, w_substr, - w_start, w_end) - return space.wrap(self.count(substr, start, end)) + self, start, end = _convert_idx_params(space, w_self, w_start, w_end) + return space.wrap(self.count(w_substr._value, start, end)) def unicode_split__Unicode_None_ANY(space, w_self, w_none, w_maxsplit): maxsplit = space.int_w(w_maxsplit) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit