Author: Hakan Ardo <ha...@debian.org> Branch: jit-targets Changeset: r50385:988827261d3c Date: 2011-12-11 14:25 +0100 http://bitbucket.org/pypy/pypy/changeset/988827261d3c/
Log: hg merge default diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -252,6 +252,10 @@ "use small tuples", default=False), + BoolOption("withspecialisedtuple", + "use specialised tuples", + default=False), + BoolOption("withrope", "use ropes as the string implementation", default=False, requires=[("objspace.std.withstrslice", False), @@ -365,6 +369,7 @@ config.objspace.std.suggest(optimized_list_getitem=True) config.objspace.std.suggest(getattributeshortcut=True) config.objspace.std.suggest(newshortcut=True) + config.objspace.std.suggest(withspecialisedtuple=True) #if not IS_64_BITS: # config.objspace.std.suggest(withsmalllong=True) diff --git a/pypy/conftest.py b/pypy/conftest.py --- a/pypy/conftest.py +++ b/pypy/conftest.py @@ -496,6 +496,17 @@ def setup(self): super(AppClassCollector, self).setup() cls = self.obj + # + # <hack> + for name in dir(cls): + if name.startswith('test_'): + func = getattr(cls, name, None) + code = getattr(func, 'func_code', None) + if code and code.co_flags & 32: + raise AssertionError("unsupported: %r is a generator " + "app-level test method" % (name,)) + # </hack> + # space = cls.space clsname = cls.__name__ if self.config.option.runappdirect: diff --git a/pypy/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py --- a/pypy/jit/tl/pypyjit_demo.py +++ b/pypy/jit/tl/pypyjit_demo.py @@ -2,13 +2,15 @@ pypyjit.set_param(threshold=200) +def g(*args): + return len(args) + def f(n): - pairs = [(0.0, 1.0), (2.0, 3.0)] * n - mag = 0 - for (x1, x2) in pairs: - dx = x1 - x2 - mag += ((dx * dx ) ** (-1.5)) - return n + s = 0 + for i in range(n): + l = [i, n, 2] + s += g(*l) + return s try: print f(301) diff --git a/pypy/module/_hashlib/interp_hashlib.py b/pypy/module/_hashlib/interp_hashlib.py --- a/pypy/module/_hashlib/interp_hashlib.py +++ b/pypy/module/_hashlib/interp_hashlib.py @@ -21,11 +21,11 @@ class W_Hash(Wrappable): ctx = lltype.nullptr(ropenssl.EVP_MD_CTX.TO) - _block_size = -1 def __init__(self, space, name): self.name = name - self.digest_size = self.compute_digest_size() + digest_type = self.digest_type_by_name(space) + self.digest_size = rffi.getintfield(digest_type, 'c_md_size') # Allocate a lock for each HASH object. # An optimization would be to not release the GIL on small requests, @@ -34,21 +34,22 @@ ctx = lltype.malloc(ropenssl.EVP_MD_CTX.TO, flavor='raw') rgc.add_memory_pressure(HASH_MALLOC_SIZE + self.digest_size) + ropenssl.EVP_DigestInit(ctx, digest_type) self.ctx = ctx - def initdigest(self, space, name): - digest = ropenssl.EVP_get_digestbyname(name) - if not digest: - raise OperationError(space.w_ValueError, - space.wrap("unknown hash function")) - ropenssl.EVP_DigestInit(self.ctx, digest) - def __del__(self): # self.lock.free() if self.ctx: ropenssl.EVP_MD_CTX_cleanup(self.ctx) lltype.free(self.ctx, flavor='raw') + def digest_type_by_name(self, space): + digest_type = ropenssl.EVP_get_digestbyname(self.name) + if not digest_type: + raise OperationError(space.w_ValueError, + space.wrap("unknown hash function")) + return digest_type + def descr_repr(self, space): addrstring = self.getaddrstring(space) return space.wrap("<%s HASH object at 0x%s>" % ( @@ -87,7 +88,9 @@ return space.wrap(self.digest_size) def get_block_size(self, space): - return space.wrap(self.compute_block_size()) + digest_type = self.digest_type_by_name(space) + block_size = rffi.getintfield(digest_type, 'c_block_size') + return space.wrap(block_size) def _digest(self, space): with lltype.scoped_alloc(ropenssl.EVP_MD_CTX.TO) as ctx: @@ -99,36 +102,6 @@ ropenssl.EVP_MD_CTX_cleanup(ctx) return rffi.charpsize2str(digest, digest_size) - def compute_digest_size(self): - # XXX This isn't the nicest way, but the EVP_MD_size OpenSSL - # XXX function is defined as a C macro on OS X and would be - # XXX significantly harder to implement in another way. - # Values are digest sizes in bytes - return { - 'md5': 16, 'MD5': 16, - 'sha1': 20, 'SHA1': 20, - 'sha224': 28, 'SHA224': 28, - 'sha256': 32, 'SHA256': 32, - 'sha384': 48, 'SHA384': 48, - 'sha512': 64, 'SHA512': 64, - }.get(self.name, 0) - - def compute_block_size(self): - if self._block_size != -1: - return self._block_size - # XXX This isn't the nicest way, but the EVP_MD_CTX_block_size - # XXX OpenSSL function is defined as a C macro on some systems - # XXX and would be significantly harder to implement in - # XXX another way. - self._block_size = { - 'md5': 64, 'MD5': 64, - 'sha1': 64, 'SHA1': 64, - 'sha224': 64, 'SHA224': 64, - 'sha256': 64, 'SHA256': 64, - 'sha384': 128, 'SHA384': 128, - 'sha512': 128, 'SHA512': 128, - }.get(self.name, 0) - return self._block_size W_Hash.typedef = TypeDef( 'HASH', @@ -142,11 +115,11 @@ digestsize=GetSetProperty(W_Hash.get_digest_size), block_size=GetSetProperty(W_Hash.get_block_size), ) +W_Hash.acceptable_as_base_class = False @unwrap_spec(name=str, string='bufferstr') def new(space, name, string=''): w_hash = W_Hash(space, name) - w_hash.initdigest(space, name) w_hash.update(space, string) return space.wrap(w_hash) @@ -158,6 +131,6 @@ return new(space, name, string) return new_hash -for name in algorithms: - newname = 'new_%s' % (name,) - globals()[newname] = make_new_hash(name, newname) +for _name in algorithms: + _newname = 'new_%s' % (_name,) + globals()[_newname] = make_new_hash(_name, _newname) diff --git a/pypy/module/_hashlib/test/test_hashlib.py b/pypy/module/_hashlib/test/test_hashlib.py --- a/pypy/module/_hashlib/test/test_hashlib.py +++ b/pypy/module/_hashlib/test/test_hashlib.py @@ -80,28 +80,27 @@ _hashlib.openssl_sha1(b).digest() def test_extra_algorithms(self): - import _hashlib - test_string = "Nobody inspects the spammish repetition" expected_results = { "md5": "bb649c83dd1ea5c9d9dec9a18df0ffe9", "md4": "c275b8454684ea416b93d7a418b43176", "mdc2": None, # XXX find the correct expected value "sha": "e2b0a8609b47c58e5d984c9ccfe69f9b654b032b", "ripemd160": "cc4a5ce1b3df48aec5d22d1f16b894a0b894eccc", - "whirlpool": "1a22b79fe5afda02c63a25927193ed01dc718b74" - "026e597608ce431f9c3d2c9e74a7350b7fbb7c5d" - "4effe5d7a31879b8b7a10fd2f544c4ca268ecc6793923583", + "whirlpool": ("1a22b79fe5afda02c63a25927193ed01dc718b74" + "026e597608ce431f9c3d2c9e74a7350b7fbb7c5d" + "4effe5d7a31879b8b7a10fd2f544c4ca268ecc6793923583"), } - def extracheck(hash_name, expected): + import _hashlib + test_string = "Nobody inspects the spammish repetition" + for hash_name, expected in sorted(expected_results.items()): try: m = _hashlib.new(hash_name) except ValueError, e: - skip('%s: %s' % (hash_name, e)) + print 'skipped %s: %s' % (hash_name, e) + continue m.update(test_string) got = m.hexdigest() assert got and type(got) is str and len(got) % 2 == 0 got.decode('hex') if expected is not None: assert got == expected - for hash_name, expected in sorted(expected_results.items()): - yield extracheck, hash_name, expected diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py --- a/pypy/module/cpyext/methodobject.py +++ b/pypy/module/cpyext/methodobject.py @@ -14,7 +14,6 @@ METH_VARARGS, build_type_checkers, PyObjectFields, bootstrap_function) from pypy.module.cpyext.pyerrors import PyErr_Occurred from pypy.rlib.objectmodel import we_are_translated -from pypy.objspace.std.tupleobject import W_TupleObject PyCFunction_typedef = rffi.COpaquePtr(typedef='PyCFunction') PyCFunction = lltype.Ptr(lltype.FuncType([PyObject, PyObject], PyObject)) diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py --- a/pypy/module/cpyext/sequence.py +++ b/pypy/module/cpyext/sequence.py @@ -42,11 +42,11 @@ which case o is returned. Use PySequence_Fast_GET_ITEM() to access the members of the result. Returns NULL on failure. If the object is not a sequence, raises TypeError with m as the message text.""" - if (space.is_true(space.isinstance(w_obj, space.w_list)) or - space.is_true(space.isinstance(w_obj, space.w_tuple))): + if (isinstance(w_obj, listobject.W_ListObject) or + isinstance(w_obj, tupleobject.W_TupleObject)): return w_obj try: - return space.newtuple(space.fixedview(w_obj)) + return tupleobject.W_TupleObject(space.fixedview(w_obj)) except OperationError: raise OperationError(space.w_TypeError, space.wrap(rffi.charp2str(m))) diff --git a/pypy/module/cpyext/tupleobject.py b/pypy/module/cpyext/tupleobject.py --- a/pypy/module/cpyext/tupleobject.py +++ b/pypy/module/cpyext/tupleobject.py @@ -6,13 +6,12 @@ borrow_from, make_ref, from_ref) from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall from pypy.objspace.std.tupleobject import W_TupleObject -from pypy.objspace.std.smalltupleobject import W_SmallTupleObject PyTuple_Check, PyTuple_CheckExact = build_type_checkers("Tuple") @cpython_api([Py_ssize_t], PyObject) def PyTuple_New(space, size): - return space.newtuple([space.w_None] * size) + return W_TupleObject([space.w_None] * size) @cpython_api([PyObject, Py_ssize_t, PyObject], rffi.INT_real, error=-1) def PyTuple_SetItem(space, w_t, pos, w_obj): @@ -24,12 +23,12 @@ return 0 def _setitem_tuple(w_t, pos, w_obj): - if isinstance(w_t, W_TupleObject): - w_t.wrappeditems[pos] = w_obj - elif isinstance(w_t, W_SmallTupleObject): - w_t.setitem(pos, w_obj) - else: - assert False + # this function checks that w_t is really a W_TupleObject. It + # should only ever be called with a freshly built tuple from + # PyTuple_New(), which always return a W_TupleObject, even if there + # are also other implementations of tuples. + assert isinstance(w_t, W_TupleObject) + w_t.wrappeditems[pos] = w_obj @cpython_api([PyObject, Py_ssize_t], PyObject) def PyTuple_GetItem(space, w_t, pos): diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py --- a/pypy/module/micronumpy/interp_boxes.py +++ b/pypy/module/micronumpy/interp_boxes.py @@ -91,9 +91,6 @@ descr_neg = _unaryop_impl("negative") descr_abs = _unaryop_impl("absolute") - def descr_tolist(self, space): - return self.get_dtype(space).itemtype.to_builtin_type(space, self) - class W_BoolBox(W_GenericBox, PrimitiveBox): descr__new__, get_dtype = new_dtype_getter("bool") @@ -182,8 +179,6 @@ __neg__ = interp2app(W_GenericBox.descr_neg), __abs__ = interp2app(W_GenericBox.descr_abs), - - tolist = interp2app(W_GenericBox.descr_tolist), ) W_BoolBox.typedef = TypeDef("bool_", W_GenericBox.typedef, diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py --- a/pypy/module/micronumpy/interp_numarray.py +++ b/pypy/module/micronumpy/interp_numarray.py @@ -876,17 +876,6 @@ arr.setshape(space, new_shape) return arr - def descr_tolist(self, space): - if len(self.shape) == 0: - assert isinstance(self, Scalar) - return self.value.descr_tolist(space) - w_result = space.newlist([]) - for i in range(self.shape[0]): - space.call_method(w_result, "append", - space.call_method(self.descr_getitem(space, space.wrap(i)), "tolist") - ) - return w_result - def descr_mean(self, space): return space.div(self.descr_sum(space), space.wrap(self.find_size())) @@ -1496,7 +1485,6 @@ copy = interp2app(BaseArray.descr_copy), reshape = interp2app(BaseArray.descr_reshape), - tolist = interp2app(BaseArray.descr_tolist), ) diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py --- a/pypy/module/micronumpy/test/test_numarray.py +++ b/pypy/module/micronumpy/test/test_numarray.py @@ -879,45 +879,6 @@ b[0] = 3 assert b.__debug_repr__() == 'Call2(add, forced=Array)' - def test_tolist_scalar(self): - from numpypy import int32, bool_ - x = int32(23) - assert x.tolist() == 23 - assert type(x.tolist()) is int - y = bool_(True) - assert y.tolist() is True - - def test_tolist_zerodim(self): - from numpypy import array - x = array(3) - assert x.tolist() == 3 - assert type(x.tolist()) is int - - def test_tolist_singledim(self): - from numpypy import array - a = array(range(5)) - assert a.tolist() == [0, 1, 2, 3, 4] - assert type(a.tolist()[0]) is int - b = array([0.2, 0.4, 0.6]) - assert b.tolist() == [0.2, 0.4, 0.6] - - def test_tolist_multidim(self): - from numpypy import array - a = array([[1, 2], [3, 4]]) - assert a.tolist() == [[1, 2], [3, 4]] - - def test_tolist_view(self): - from numpypy import array - a = array([[1,2],[3,4]]) - assert (a + a).tolist() == [[2, 4], [6, 8]] - - def test_tolist_slice(self): - from numpypy import array - a = array([[17.1, 27.2], [40.3, 50.3]]) - assert a[:,0].tolist() == [17.1, 40.3] - assert a[0].tolist() == [17.1, 27.2] - - class AppTestMultiDim(BaseNumpyAppTest): def test_init(self): import numpypy diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -78,9 +78,6 @@ w_obj.__init__(self._coerce(space, w_item).value) return w_obj - def to_builtin_type(self, space, box): - return space.wrap(self.unbox(box)) - def _coerce(self, space, w_item): raise NotImplementedError 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 @@ -694,14 +694,16 @@ return self.wrap(r) @jit.look_inside_iff(lambda self, w_list: - jit.isconstant(w_list.length()) and w_list.length() < UNROLL_CUTOFF) + jit.isconstant(w_list.length()) and w_list.length() < UNROLL_CUTOFF) def getitems_copy(self, w_list): return [self.wrap(item) for item in self.unerase(w_list.lstorage)] @jit.unroll_safe def getitems_unroll(self, w_list): return [self.wrap(item) for item in self.unerase(w_list.lstorage)] - @jit.dont_look_inside + + @jit.look_inside_iff(lambda self, w_list: + jit.isconstant(w_list.length()) and w_list.length() < UNROLL_CUTOFF) def getitems_fixedsize(self, w_list): return self.getitems_unroll(w_list) diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py --- a/pypy/objspace/std/model.py +++ b/pypy/objspace/std/model.py @@ -15,6 +15,7 @@ _registered_implementations.add(implcls) option_to_typename = { + "withspecialisedtuple" : ["specialisedtupleobject.W_SpecialisedTupleObject"], "withsmalltuple" : ["smalltupleobject.W_SmallTupleObject"], "withsmallint" : ["smallintobject.W_SmallIntObject"], "withsmalllong" : ["smalllongobject.W_SmallLongObject"], @@ -261,6 +262,11 @@ self.typeorder[smalltupleobject.W_SmallTupleObject] += [ (tupleobject.W_TupleObject, smalltupleobject.delegate_SmallTuple2Tuple)] + if config.objspace.std.withspecialisedtuple: + from pypy.objspace.std import specialisedtupleobject + self.typeorder[specialisedtupleobject.W_SpecialisedTupleObject] += [ + (tupleobject.W_TupleObject, specialisedtupleobject.delegate_SpecialisedTuple2Tuple)] + # put W_Root everywhere self.typeorder[W_Root] = [] for type in self.typeorder: diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py --- a/pypy/objspace/std/objspace.py +++ b/pypy/objspace/std/objspace.py @@ -29,7 +29,7 @@ from pypy.objspace.std.sliceobject import W_SliceObject from pypy.objspace.std.smallintobject import W_SmallIntObject from pypy.objspace.std.stringobject import W_StringObject -from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.tupleobject import W_AbstractTupleObject from pypy.objspace.std.typeobject import W_TypeObject # types @@ -391,8 +391,8 @@ self.wrap("expected length %d, got %d" % (expected, got))) def unpackiterable(self, w_obj, expected_length=-1): - if isinstance(w_obj, W_TupleObject): - t = w_obj.wrappeditems[:] + if isinstance(w_obj, W_AbstractTupleObject): + t = w_obj.getitems_copy() elif isinstance(w_obj, W_ListObject): t = w_obj.getitems_copy() else: @@ -405,8 +405,8 @@ def fixedview(self, w_obj, expected_length=-1, unroll=False): """ Fast paths """ - if isinstance(w_obj, W_TupleObject): - t = w_obj.wrappeditems + if isinstance(w_obj, W_AbstractTupleObject): + t = w_obj.tolist() elif isinstance(w_obj, W_ListObject): if unroll: t = w_obj.getitems_unroll() @@ -430,8 +430,8 @@ def listview(self, w_obj, expected_length=-1): if isinstance(w_obj, W_ListObject): t = w_obj.getitems() - elif isinstance(w_obj, W_TupleObject): - t = w_obj.wrappeditems[:] + elif isinstance(w_obj, W_AbstractTupleObject): + t = w_obj.getitems_copy() else: return ObjSpace.unpackiterable(self, w_obj, expected_length) if expected_length != -1 and len(t) != expected_length: 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 @@ -9,13 +9,14 @@ from pypy.interpreter import gateway from pypy.rlib.debug import make_sure_not_resized from pypy.rlib.unroll import unrolling_iterable +from pypy.tool.sourcetools import func_with_new_name from pypy.objspace.std.tupleobject import W_AbstractTupleObject, W_TupleObject class W_SmallTupleObject(W_AbstractTupleObject): from pypy.objspace.std.tupletype import tuple_typedef as typedef - def tolist(self): - raise NotImplementedError + #def tolist(self): --- inherited from W_AbstractTupleObject + # raise NotImplementedError def length(self): raise NotImplementedError @@ -51,6 +52,9 @@ l[i] = getattr(self, 'w_value%s' % i) return l + # same source code, but builds and returns a resizable list + getitems_copy = func_with_new_name(tolist, 'getitems_copy') + def length(self): return n diff --git a/pypy/objspace/std/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/specialisedtupleobject.py @@ -0,0 +1,302 @@ +from pypy.interpreter.error import OperationError +from pypy.objspace.std.model import registerimplementation +from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.multimethod import FailedToImplement +from pypy.objspace.std.tupleobject import W_AbstractTupleObject +from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.rlib.rarithmetic import intmask +from pypy.rlib.objectmodel import compute_hash +from pypy.rlib.unroll import unrolling_iterable +from pypy.tool.sourcetools import func_with_new_name + +class NotSpecialised(Exception): + pass + +class W_SpecialisedTupleObject(W_AbstractTupleObject): + from pypy.objspace.std.tupletype import tuple_typedef as typedef + __slots__ = [] + + def __repr__(self): + """ representation for debugging purposes """ + reprlist = [repr(item) for item in self._to_unwrapped_list()] + return "%s(%s)" % (self.__class__.__name__, ', '.join(reprlist)) + + #def tolist(self): --- inherited from W_AbstractTupleObject + # raise NotImplementedError + + def _to_unwrapped_list(self): + "NOT_RPYTHON" + raise NotImplementedError + + def length(self): + raise NotImplementedError + + def getitem(self, index): + raise NotImplementedError + + def hash(self, space): + raise NotImplementedError + + def eq(self, space, w_other): + raise NotImplementedError + + def setitem(self, index, w_item): + raise NotImplementedError + + def unwrap(self, space): + return tuple(self._to_unwrapped_list()) + + def delegating(self): + pass # for tests only + + +def make_specialised_class(typetuple): + assert type(typetuple) == tuple + + nValues = len(typetuple) + iter_n = unrolling_iterable(range(nValues)) + + class cls(W_SpecialisedTupleObject): + def __init__(self, space, *values_w): + self.space = space + assert len(values_w) == nValues + for i in iter_n: + w_obj = values_w[i] + val_type = typetuple[i] + if val_type == int: + unwrapped = space.int_w(w_obj) + elif val_type == float: + unwrapped = space.float_w(w_obj) + elif val_type == str: + unwrapped = space.str_w(w_obj) + elif val_type == object: + unwrapped = w_obj + else: + raise AssertionError + setattr(self, 'value%s' % i, unwrapped) + + def length(self): + return nValues + + def tolist(self): + list_w = [None] * nValues + for i in iter_n: + value = getattr(self, 'value%s' % i) + if typetuple[i] != object: + value = self.space.wrap(value) + list_w[i] = value + return list_w + + # same source code, but builds and returns a resizable list + getitems_copy = func_with_new_name(tolist, 'getitems_copy') + + def _to_unwrapped_list(self): + "NOT_RPYTHON" + list_w = [None] * nValues + for i in iter_n: + value = getattr(self, 'value%s' % i) + if typetuple[i] == object: + value = self.space.unwrap(value) + list_w[i] = value + return list_w + + def hash(self, space): + # XXX duplicate logic from tupleobject.py + mult = 1000003 + x = 0x345678 + z = nValues + for i in iter_n: + value = getattr(self, 'value%s' % i) + if typetuple[i] == object: + y = space.int_w(space.hash(value)) + elif typetuple[i] == float: + # get the correct hash for float which is an + # integer & other less frequent cases + from pypy.objspace.std.floatobject import _hash_float + y = _hash_float(space, value) + else: + y = compute_hash(value) + x = (x ^ y) * mult + z -= 1 + mult += 82520 + z + z + x += 97531 + return space.wrap(intmask(x)) + + def _eq(self, w_other): + if not isinstance(w_other, cls): + # if we are not comparing same types, give up + raise FailedToImplement + for i in iter_n: + myval = getattr(self, 'value%s' % i) + otherval = getattr(w_other, 'value%s' % i) + if typetuple[i] == object: + if not self.space.eq_w(myval, otherval): + return False + else: + if myval != otherval: + return False + else: + return True + + def eq(self, space, w_other): + return space.newbool(self._eq(w_other)) + + def ne(self, space, w_other): + return space.newbool(not self._eq(w_other)) + +## def _compare(self, compare_op, w_other): +## if not isinstance(w_other, cls): +## raise FailedToImplement +## ncmp = min(self.length(), w_other.length()) +## for i in iter_n: +## if typetuple[i] == Any:#like space.eq on wrapped or two params? +## raise FailedToImplement +## if ncmp > i: +## l_val = getattr(self, 'value%s' % i) +## r_val = getattr(w_other, 'value%s' % i) +## if l_val != r_val: +## return compare_op(l_val, r_val) +## return compare_op(self.length(), w_other.length()) + + def getitem(self, index): + for i in iter_n: + if index == i: + value = getattr(self, 'value%s' % i) + if typetuple[i] != object: + value = self.space.wrap(value) + return value + raise IndexError + + cls.__name__ = ('W_SpecialisedTupleObject_' + + ''.join([t.__name__[0] for t in typetuple])) + _specialisations.append(cls) + return cls + +# ---------- current specialized versions ---------- + +_specialisations = [] +Cls_ii = make_specialised_class((int, int)) +Cls_is = make_specialised_class((int, str)) +Cls_io = make_specialised_class((int, object)) +Cls_si = make_specialised_class((str, int)) +Cls_ss = make_specialised_class((str, str)) +Cls_so = make_specialised_class((str, object)) +Cls_oi = make_specialised_class((object, int)) +Cls_os = make_specialised_class((object, str)) +Cls_oo = make_specialised_class((object, object)) +Cls_ff = make_specialised_class((float, float)) +Cls_ooo = make_specialised_class((object, object, object)) + +def makespecialisedtuple(space, list_w): + if len(list_w) == 2: + w_arg1, w_arg2 = list_w + w_type1 = space.type(w_arg1) + w_type2 = space.type(w_arg2) + # + if w_type1 is space.w_int: + if w_type2 is space.w_int: + return Cls_ii(space, w_arg1, w_arg2) + elif w_type2 is space.w_str: + return Cls_is(space, w_arg1, w_arg2) + else: + return Cls_io(space, w_arg1, w_arg2) + # + elif w_type1 is space.w_str: + if w_type2 is space.w_int: + return Cls_si(space, w_arg1, w_arg2) + elif w_type2 is space.w_str: + return Cls_ss(space, w_arg1, w_arg2) + else: + return Cls_so(space, w_arg1, w_arg2) + # + elif w_type1 is space.w_float and w_type2 is space.w_float: + return Cls_ff(space, w_arg1, w_arg2) + # + else: + if w_type2 is space.w_int: + return Cls_oi(space, w_arg1, w_arg2) + elif w_type2 is space.w_str: + return Cls_os(space, w_arg1, w_arg2) + else: + return Cls_oo(space, w_arg1, w_arg2) + # + elif len(list_w) == 3: + return Cls_ooo(space, list_w[0], list_w[1], list_w[2]) + else: + raise NotSpecialised + +# ____________________________________________________________ + +registerimplementation(W_SpecialisedTupleObject) + +def delegate_SpecialisedTuple2Tuple(space, w_specialised): + w_specialised.delegating() + return W_TupleObject(w_specialised.tolist()) + +def len__SpecialisedTuple(space, w_tuple): + return space.wrap(w_tuple.length()) + +def getitem__SpecialisedTuple_ANY(space, w_tuple, w_index): + index = space.getindex_w(w_index, space.w_IndexError, "tuple index") + if index < 0: + index += w_tuple.length() + try: + return w_tuple.getitem(index) + except IndexError: + raise OperationError(space.w_IndexError, + space.wrap("tuple index out of range")) + +def getitem__SpecialisedTuple_Slice(space, w_tuple, w_slice): + length = w_tuple.length() + start, stop, step, slicelength = w_slice.indices4(space, length) + assert slicelength >= 0 + subitems = [None] * slicelength + for i in range(slicelength): + subitems[i] = w_tuple.getitem(start) + start += step + return space.newtuple(subitems) + +def mul_specialisedtuple_times(space, w_tuple, w_times): + try: + times = space.getindex_w(w_times, space.w_OverflowError) + except OperationError, e: + if e.match(space, space.w_TypeError): + raise FailedToImplement + raise + if times == 1 and space.type(w_tuple) == space.w_tuple: + return w_tuple + items = w_tuple.tolist() + return space.newtuple(items * times) + +def mul__SpecialisedTuple_ANY(space, w_tuple, w_times): + return mul_specialisedtuple_times(space, w_tuple, w_times) + +def mul__ANY_SpecialisedTuple(space, w_times, w_tuple): + return mul_specialisedtuple_times(space, w_tuple, w_times) + +def eq__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): + return w_tuple1.eq(space, w_tuple2) + +def ne__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): + return w_tuple1.ne(space, w_tuple2) + +##from operator import lt, le, ge, gt + +##def lt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): +## return space.newbool(w_tuple1._compare(lt, w_tuple2)) + +##def le__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): +## return space.newbool(w_tuple1._compare(le, w_tuple2)) + +##def ge__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): +## return space.newbool(w_tuple1._compare(ge, w_tuple2)) + +##def gt__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2): +## return space.newbool(w_tuple1._compare(gt, w_tuple2)) + +def hash__SpecialisedTuple(space, w_tuple): + return w_tuple.hash(space) + +from pypy.objspace.std import tupletype +register_all(vars(), tupletype) diff --git a/pypy/objspace/std/test/test_specialisedtupleobject.py b/pypy/objspace/std/test/test_specialisedtupleobject.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/test/test_specialisedtupleobject.py @@ -0,0 +1,234 @@ +import py, sys +from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.specialisedtupleobject import W_SpecialisedTupleObject +from pypy.objspace.std.specialisedtupleobject import _specialisations +from pypy.interpreter.error import OperationError +from pypy.conftest import gettestobjspace, option +from pypy.objspace.std.test import test_tupleobject +from pypy.interpreter import gateway + + +for cls in _specialisations: + globals()[cls.__name__] = cls + + +class TestW_SpecialisedTupleObject(): + + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withspecialisedtuple": True}) + + def test_isspecialisedtupleobjectintint(self): + w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) + assert isinstance(w_tuple, W_SpecialisedTupleObject_ii) + + def test_isnotspecialisedtupleobject(self): + w_tuple = self.space.newtuple([self.space.wrap({})]) + assert not isinstance(w_tuple, W_SpecialisedTupleObject) + + def test_specialisedtupleclassname(self): + w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) + assert w_tuple.__class__.__name__ == 'W_SpecialisedTupleObject_ii' + + def test_hash_against_normal_tuple(self): + N_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": False}) + S_space = gettestobjspace(**{"objspace.std.withspecialisedtuple": True}) + + def hash_test(values): + N_values_w = [N_space.wrap(value) for value in values] + S_values_w = [S_space.wrap(value) for value in values] + N_w_tuple = N_space.newtuple(N_values_w) + S_w_tuple = S_space.newtuple(S_values_w) + + assert isinstance(S_w_tuple, W_SpecialisedTupleObject) + assert isinstance(N_w_tuple, W_TupleObject) + assert not N_space.is_true(N_space.eq(N_w_tuple, S_w_tuple)) + assert S_space.is_true(S_space.eq(N_w_tuple, S_w_tuple)) + assert S_space.is_true(S_space.eq(N_space.hash(N_w_tuple), S_space.hash(S_w_tuple))) + + hash_test([1,2]) + hash_test([1.5,2.8]) + hash_test([1.0,2.0]) + hash_test(['arbitrary','strings']) + hash_test([1,(1,2,3,4)]) + hash_test([1,(1,2)]) + hash_test([1,('a',2)]) + hash_test([1,()]) + hash_test([1,2,3]) + + +class AppTestW_SpecialisedTupleObject: + + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withspecialisedtuple": True}) + def forbid_delegation(space, w_tuple): + def delegation_forbidden(): + # haaaack + co = sys._getframe(2).f_code + if co.co_name.startswith('_mm_repr_tuple'): + return + raise OperationError(space.w_ReferenceError, w_tuple) + w_tuple.delegating = delegation_forbidden + return w_tuple + if option.runappdirect: + cls.w_forbid_delegation = lambda self, x: x + cls.test_delegation = lambda self: skip("runappdirect") + else: + cls.w_forbid_delegation = cls.space.wrap( + gateway.interp2app(forbid_delegation)) + + def w_isspecialised(self, obj, expected=''): + import __pypy__ + r = __pypy__.internal_repr(obj) + print obj, '==>', r, ' (expected: %r)' % expected + return ("SpecialisedTupleObject" + expected) in r + + def test_createspecialisedtuple(self): + spec = {int: 'i', + float: 'f', + str: 's', + list: 'o'} + # + for x in [42, 4.2, "foo", []]: + for y in [43, 4.3, "bar", []]: + expected1 = spec[type(x)] + expected2 = spec[type(y)] + if (expected1 == 'f') ^ (expected2 == 'f'): + if expected1 == 'f': expected1 = 'o' + if expected2 == 'f': expected2 = 'o' + obj = (x, y) + assert self.isspecialised(obj, '_' + expected1 + expected2) + # + obj = (1, 2, 3) + assert self.isspecialised(obj, '_ooo') + + def test_delegation(self): + t = self.forbid_delegation((42, 43)) + raises(ReferenceError, t.__getslice__, 0, 1) + + def test_len(self): + t = self.forbid_delegation((42,43)) + assert len(t) == 2 + + def test_notspecialisedtuple(self): + assert not self.isspecialised((42,43,44,45)) + assert not self.isspecialised((1.5,)) + + def test_slicing_to_specialised(self): + t = (1, 2, 3) + assert self.isspecialised(t[0:2]) + t = (1, '2', 3) + assert self.isspecialised(t[0:5:2]) + + def test_adding_to_specialised(self): + t = (1,) + assert self.isspecialised(t + (2,)) + + def test_multiply_to_specialised(self): + t = (1,) + assert self.isspecialised(t * 2) + + def test_slicing_from_specialised(self): + t = (1, 2, 3) + assert t[0:2:1] == (1, 2) + + def test_eq_no_delegation(self): + t = (1,) + a = self.forbid_delegation(t + (2,)) + b = (1, 2) + assert a == b + + c = (2, 1) + assert not a == c + + def test_eq_can_delegate(self): + a = (1,2) + b = (1,3,2) + assert not a == b + + values = [2, 2L, 2.0, 1, 1L, 1.0] + for x in values: + for y in values: + assert ((1,2) == (x,y)) == (1 == x and 2 == y) + + def test_neq(self): + a = self.forbid_delegation((1,2)) + b = (1,) + b = b+(2,) + assert not a != b + + c = (1,3) + assert a != c + + def test_ordering(self): + a = (1,2) #self.forbid_delegation((1,2)) --- code commented out + assert a < (2,2) + assert a < (1,3) + assert not a < (1,2) + + assert a <= (2,2) + assert a <= (1,2) + assert not a <= (1,1) + + assert a >= (0,2) + assert a >= (1,2) + assert not a >= (1,3) + + assert a > (0,2) + assert a > (1,1) + assert not a > (1,3) + + assert (2,2) > a + assert (1,3) > a + assert not (1,2) > a + + assert (2,2) >= a + assert (1,2) >= a + assert not (1,1) >= a + + assert (0,2) <= a + assert (1,2) <= a + assert not (1,3) <= a + + assert (0,2) < a + assert (1,1) < a + assert not (1,3) < a + + def test_hash(self): + a = (1,2) + b = (1,) + b += (2,) # else a and b refer to same constant + assert hash(a) == hash(b) + + c = (2,4) + assert hash(a) != hash(c) + + assert hash(a) == hash((1L, 2L)) == hash((1.0, 2.0)) == hash((1.0, 2L)) + + def test_getitem(self): + t = self.forbid_delegation((5,3)) + assert (t)[0] == 5 + assert (t)[1] == 3 + assert (t)[-1] == 3 + assert (t)[-2] == 5 + raises(IndexError, "t[2]") + raises(IndexError, "t[-3]") + + def test_three_tuples(self): + b = self.forbid_delegation((1, 2, 3)) + c = (1,) + d = c + (2, 3) + assert self.isspecialised(d) + assert b == d + + def test_mongrel(self): + a = self.forbid_delegation((1, 2.2, '333')) + assert self.isspecialised(a) + assert len(a) == 3 + assert a[0] == 1 and a[1] == 2.2 and a[2] == '333' + b = ('333',) + assert a == (1, 2.2,) + b + assert not a != (1, 2.2) + b + + +class AppTestAll(test_tupleobject.AppTestW_TupleObject): + pass diff --git a/pypy/objspace/std/test/test_tupleobject.py b/pypy/objspace/std/test/test_tupleobject.py --- a/pypy/objspace/std/test/test_tupleobject.py +++ b/pypy/objspace/std/test/test_tupleobject.py @@ -280,6 +280,8 @@ assert () * 10 == () assert (5,) * 3 == (5,5,5) assert (5,2) * 2 == (5,2,5,2) + + def test_mul_identity(self): t = (1,2,3) assert (t * 1) is t 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 @@ -12,6 +12,15 @@ class W_AbstractTupleObject(W_Object): __slots__ = () + def tolist(self): + "Returns the items, as a fixed-size list." + raise NotImplementedError + + def getitems_copy(self): + "Returns a copy of the items, as a resizable list." + raise NotImplementedError + + class W_TupleObject(W_AbstractTupleObject): from pypy.objspace.std.tupletype import tuple_typedef as typedef _immutable_fields_ = ['wrappeditems[*]'] @@ -29,6 +38,12 @@ items = [space.unwrap(w_item) for w_item in w_tuple.wrappeditems] return tuple(items) + def tolist(self): + return self.wrappeditems + + def getitems_copy(self): + return self.wrappeditems[:] # returns a resizable list + registerimplementation(W_TupleObject) diff --git a/pypy/objspace/std/tupletype.py b/pypy/objspace/std/tupletype.py --- a/pypy/objspace/std/tupletype.py +++ b/pypy/objspace/std/tupletype.py @@ -5,6 +5,14 @@ def wraptuple(space, list_w): from pypy.objspace.std.tupleobject import W_TupleObject + + if space.config.objspace.std.withspecialisedtuple: + from specialisedtupleobject import makespecialisedtuple, NotSpecialised + try: + return makespecialisedtuple(space, list_w) + except NotSpecialised: + pass + if space.config.objspace.std.withsmalltuple: from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 from pypy.objspace.std.smalltupleobject import W_SmallTupleObject3 diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -110,6 +110,10 @@ 'struct GENERAL_NAME_st', [('type', rffi.INT), ]) + EVP_MD_st = rffi_platform.Struct( + 'EVP_MD', + [('md_size', rffi.INT), + ('block_size', rffi.INT)]) EVP_MD_SIZE = rffi_platform.SizeOf('EVP_MD') EVP_MD_CTX_SIZE = rffi_platform.SizeOf('EVP_MD_CTX') @@ -258,7 +262,7 @@ [BIO, rffi.VOIDP, rffi.VOIDP, rffi.VOIDP], X509) EVP_MD_CTX = rffi.COpaquePtr('EVP_MD_CTX', compilation_info=eci) -EVP_MD = rffi.COpaquePtr('EVP_MD', compilation_info=eci) +EVP_MD = lltype.Ptr(EVP_MD_st) OpenSSL_add_all_digests = external( 'OpenSSL_add_all_digests', [], lltype.Void) diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py --- a/pypy/tool/pytest/appsupport.py +++ b/pypy/tool/pytest/appsupport.py @@ -63,7 +63,10 @@ exec_ = eval def repr(self, w_value): - return self.space.unwrap(self.space.repr(w_value)) + try: + return self.space.unwrap(self.space.repr(w_value)) + except Exception, e: + return "<Sorry, exception while trying to do repr, %r>"%e def is_true(self, w_value): return self.space.is_true(w_value) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit