Author: Lukas Diekmann <lukas.diekm...@uni-duesseldorf.de> Branch: Changeset: r44437:2a73c37a0c1f Date: 2011-03-16 14:50 +0100 http://bitbucket.org/pypy/pypy/changeset/2a73c37a0c1f/
Log: merge diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -237,6 +237,10 @@ "(the empty string and potentially single-char strings)", default=False), + BoolOption("withsmalltuple", + "use small tuples", + default=False), + BoolOption("withrope", "use ropes as the string implementation", default=False, requires=[("objspace.std.withstrslice", False), diff --git a/pypy/doc/config/objspace.std.withsmalltuple.txt b/pypy/doc/config/objspace.std.withsmalltuple.txt new file mode 100644 --- /dev/null +++ b/pypy/doc/config/objspace.std.withsmalltuple.txt @@ -0,0 +1,1 @@ +Use small tuple objects for sizes from 1 to 3 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 = { + "withsmalltuple" : ["smalltupleobject.W_SmallTupleObject"], "withsmallint" : ["smallintobject.W_SmallIntObject"], "withsmalllong" : ["smalllongobject.W_SmallLongObject"], "withstrslice" : ["strsliceobject.W_StringSliceObject"], @@ -72,6 +73,7 @@ from pypy.objspace.std import smallintobject from pypy.objspace.std import smalllongobject from pypy.objspace.std import tupleobject + from pypy.objspace.std import smalltupleobject from pypy.objspace.std import listobject from pypy.objspace.std import dictmultiobject from pypy.objspace.std import stringobject @@ -255,6 +257,9 @@ (listobject.W_ListObject, rangeobject.delegate_range2list), ] + if config.objspace.std.withsmalltuple: + self.typeorder[smalltupleobject.W_SmallTupleObject] += [ + (tupleobject.W_TupleObject, smalltupleobject.delegate_SmallTuple2Tuple)] # put W_Root everywhere self.typeorder[W_Root] = [] 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 @@ -295,9 +295,10 @@ return newlong(self, val) def newtuple(self, list_w): + from pypy.objspace.std.tupletype import wraptuple assert isinstance(list_w, list) make_sure_not_resized(list_w) - return W_TupleObject(list_w) + return wraptuple(self, list_w) def newlist(self, list_w): return W_ListObject(list_w) diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/smalltupleobject.py @@ -0,0 +1,128 @@ +from pypy.interpreter.error import OperationError +from pypy.objspace.std.model import registerimplementation, W_Object +from pypy.objspace.std.register_all import register_all +from pypy.objspace.std.inttype import wrapint +from pypy.objspace.std.multimethod import FailedToImplement +from pypy.rlib.rarithmetic import intmask +from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice +from pypy.objspace.std import slicetype +from pypy.interpreter import gateway +from pypy.rlib.debug import make_sure_not_resized +from pypy.rlib.unroll import unrolling_iterable +from pypy.objspace.std.tupleobject import W_TupleObject + +class W_SmallTupleObject(W_Object): + from pypy.objspace.std.tupletype import tuple_typedef as typedef + + def tolist(self): + raise NotImplementedError + + def length(self): + raise NotImplementedError + +def make_specialized_class(n): + iter_n = unrolling_iterable(range(n)) + class cls(W_SmallTupleObject): + + def __init__(self, values): + assert len(values) == n + for i in iter_n: + setattr(self, 'w_value%s' % i, values[i]) + + def tolist(self): + l = [None] * n + for i in iter_n: + l[i] = getattr(self, 'w_value%s' % i) + return l + + def length(self): + return n + + def getitem(self, index): + for i in iter_n: + if index == i: + return getattr(self,'w_value%s' % i) + raise IndexError + + cls.__name__ = "W_SmallTupleObject%s" % n + return cls + +W_SmallTupleObject2 = make_specialized_class(2) +W_SmallTupleObject3 = make_specialized_class(3) +W_SmallTupleObject4 = make_specialized_class(4) +W_SmallTupleObject5 = make_specialized_class(5) +W_SmallTupleObject6 = make_specialized_class(6) +W_SmallTupleObject7 = make_specialized_class(7) +W_SmallTupleObject8 = make_specialized_class(8) + +registerimplementation(W_SmallTupleObject) + +def delegate_SmallTuple2Tuple(space, w_small): + return W_TupleObject(w_small.tolist()) + +def len__SmallTuple(space, w_tuple): + return space.wrap(w_tuple.length()) + +def getitem__SmallTuple_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__SmallTuple_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_smalltuple_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__SmallTuple_ANY(space, w_tuple, w_times): + return mul_smalltuple_times(space, w_tuple, w_times) + +def mul__ANY_SmallTuple(space, w_times, w_tuple): + return mul_smalltuple_times(space, w_tuple, w_times) + +def eq__SmallTuple_SmallTuple(space, w_tuple1, w_tuple2): + if w_tuple1.length() != w_tuple2.length(): + return space.w_False + for i in range(w_tuple1.length()): + item1 = w_tuple1.getitem(i) + item2 = w_tuple2.getitem(i) + if not space.eq_w(item1, item2): + return space.w_False + return space.w_True + +def hash__SmallTuple(space, w_tuple): + # this is the CPython 2.4 algorithm (changed from 2.3) + mult = 1000003 + x = 0x345678 + z = w_tuple.length() + for w_item in w_tuple.tolist(): #XXX: remove list and run through items directly, later + y = space.int_w(space.hash(w_item)) + x = (x ^ y) * mult + z -= 1 + mult += 82520 + z + z + x += 97531 + return space.wrap(intmask(x)) + +from pypy.objspace.std import tupletype +register_all(vars(), tupletype) diff --git a/pypy/objspace/std/test/test_smalltupleobject.py b/pypy/objspace/std/test/test_smalltupleobject.py new file mode 100644 --- /dev/null +++ b/pypy/objspace/std/test/test_smalltupleobject.py @@ -0,0 +1,72 @@ +from pypy.objspace.std.tupleobject import W_TupleObject +from pypy.objspace.std.smalltupleobject import W_SmallTupleObject +from pypy.interpreter.error import OperationError +from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject +from pypy.conftest import gettestobjspace + +class AppTestW_SmallTupleObject(AppTestW_TupleObject): + + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withsmalltuple": True}) + cls.w_issmall = cls.space.appexec([], """(): + import __pypy__ + def issmall(obj): + assert "SmallTuple" in __pypy__.internal_repr(obj) + return issmall + """) + + def test_smalltuple(self): + self.issmall((1,2)) + self.issmall((1,2,3)) + + def test_slicing_to_small(self): + self.issmall((1, 2, 3)[0:2]) # SmallTuple2 + self.issmall((1, 2, 3)[0:2:1]) + + self.issmall((1, 2, 3, 4)[0:3]) # SmallTuple3 + self.issmall((1, 2, 3, 4)[0:3:1]) + + def test_adding_to_small(self): + self.issmall((1,)+(2,)) # SmallTuple2 + self.issmall((1,1)+(2,)) # SmallTuple3 + self.issmall((1,)+(2,3)) + + def test_multiply_to_small(self): + self.issmall((1,)*2) + self.issmall((1,)*3) + + def test_slicing_from_small(self): + assert (1,2)[0:1:1] == (1,) + assert (1,2,3)[0:2:1] == (1,2) + + def test_eq(self): + a = (1,2,3) + b = (1,2,3) + assert a == b + + def test_hash(self): + a = (1,2,3) + b = (1,2,3) + assert hash(a) == hash(b) + +class TestW_SmallTupleObject(): + + def setup_class(cls): + cls.space = gettestobjspace(**{"objspace.std.withsmalltuple": True}) + + def test_issmalltupleobject(self): + w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)]) + assert isinstance(w_tuple, W_SmallTupleObject) + + def test_hash_agains_normal_tuple(self): + normalspace = gettestobjspace(**{"objspace.std.withsmalltuple": False}) + w_tuple = normalspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) + + smallspace = gettestobjspace(**{"objspace.std.withsmalltuple": True}) + w_smalltuple = smallspace.newtuple([self.space.wrap(1), self.space.wrap(2)]) + + assert isinstance(w_smalltuple, W_SmallTupleObject) + assert isinstance(w_tuple, W_TupleObject) + assert not normalspace.is_true(normalspace.eq(w_tuple, w_smalltuple)) + assert smallspace.is_true(smallspace.eq(w_tuple, w_smalltuple)) + assert smallspace.is_true(smallspace.eq(normalspace.hash(w_tuple), smallspace.hash(w_smalltuple))) 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 @@ -56,12 +56,12 @@ for i in range(slicelength): subitems[i] = items[start] start += step - return W_TupleObject(subitems) + return space.newtuple(subitems) def getslice__Tuple_ANY_ANY(space, w_tuple, w_start, w_stop): length = len(w_tuple.wrappeditems) start, stop = normalize_simple_slice(space, length, w_start, w_stop) - return W_TupleObject(w_tuple.wrappeditems[start:stop]) + return space.newtuple(w_tuple.wrappeditems[start:stop]) def contains__Tuple_ANY(space, w_tuple, w_obj): for w_item in w_tuple.wrappeditems: @@ -76,7 +76,7 @@ def add__Tuple_Tuple(space, w_tuple1, w_tuple2): items1 = w_tuple1.wrappeditems items2 = w_tuple2.wrappeditems - return W_TupleObject(items1 + items2) + return space.newtuple(items1 + items2) def mul_tuple_times(space, w_tuple, w_times): try: @@ -88,7 +88,7 @@ if times == 1 and space.type(w_tuple) == space.w_tuple: return w_tuple items = w_tuple.wrappeditems - return W_TupleObject(items * times) + return space.newtuple(items * times) def mul__Tuple_ANY(space, w_tuple, w_times): return mul_tuple_times(space, w_tuple, w_times) @@ -159,7 +159,7 @@ return space.wrap(intmask(x)) def getnewargs__Tuple(space, w_tuple): - return space.newtuple([W_TupleObject(w_tuple.wrappeditems)]) + return space.newtuple([space.newtuple(w_tuple.wrappeditems)]) def tuple_count__Tuple_ANY(space, w_tuple, w_obj): count = 0 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 @@ -3,6 +3,31 @@ from pypy.objspace.std.register_all import register_all from pypy.objspace.std.stdtypedef import StdTypeDef, SMM +def wraptuple(space, list_w): + from pypy.objspace.std.tupleobject import W_TupleObject + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject3 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject4 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject5 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject6 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject7 + from pypy.objspace.std.smalltupleobject import W_SmallTupleObject8 + if space.config.objspace.std.withsmalltuple: + if len(list_w) == 2: + return W_SmallTupleObject2(list_w) + if len(list_w) == 3: + return W_SmallTupleObject3(list_w) + if len(list_w) == 4: + return W_SmallTupleObject4(list_w) + if len(list_w) == 5: + return W_SmallTupleObject5(list_w) + if len(list_w) == 6: + return W_SmallTupleObject6(list_w) + if len(list_w) == 7: + return W_SmallTupleObject7(list_w) + if len(list_w) == 8: + return W_SmallTupleObject8(list_w) + return W_TupleObject(list_w) tuple_count = SMM("count", 2, doc="count(obj) -> number of times obj appears in the tuple") _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit