[pypy-commit] pypy SpecialisedTuples: (mwp, antocuni) Create a branch with tuples specialised by type

mwp noreply at buildbot.pypy.org
Thu Nov 10 10:47:19 CET 2011


Author: Mark Pearse <mark.pearse at skynet.be>
Branch: SpecialisedTuples
Changeset: r49077:a467cb7c4dd5
Date: 2011-11-04 13:49 +0100
http://bitbucket.org/pypy/pypy/changeset/a467cb7c4dd5/

Log:	(mwp, antocuni) Create a branch with tuples specialised by type

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),
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"],
@@ -73,6 +74,7 @@
         from pypy.objspace.std import smalllongobject
         from pypy.objspace.std import tupleobject
         from pypy.objspace.std import smalltupleobject
+        from pypy.objspace.std import specialisedtupleobject
         from pypy.objspace.std import listobject
         from pypy.objspace.std import dictmultiobject
         from pypy.objspace.std import stringobject
@@ -259,6 +261,10 @@
             self.typeorder[smalltupleobject.W_SmallTupleObject] += [
                 (tupleobject.W_TupleObject, smalltupleobject.delegate_SmallTuple2Tuple)]
 
+        if config.objspace.std.withspecialisedtuple:
+            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/specialisedtupleobject.py b/pypy/objspace/std/specialisedtupleobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/specialisedtupleobject.py
@@ -0,0 +1,200 @@
+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.intobject import W_IntObject
+from pypy.objspace.std.floatobject import W_FloatObject
+from pypy.objspace.std.stringobject import W_StringObject
+from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
+from pypy.objspace.std import slicetype
+from pypy.rlib.rarithmetic import intmask
+from pypy.objspace.std.tupleobject import W_TupleObject
+
+from  types import IntType, FloatType, StringType
+
+class W_SpecialisedTupleObject(W_Object):
+    from pypy.objspace.std.tupletype import tuple_typedef as typedef
+
+    def tolist(self):
+        raise NotImplementedError
+
+    def _tolistunwrapped(self):
+        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(w_tuple, space):
+        return tuple(self.tolist)
+                        
+class W_SpecialisedTupleObject1(W_SpecialisedTupleObject):	#one element tuples
+    def __init__(self, value0):
+        raise NotImplementedError
+
+    def length(self):
+        return 1
+
+    def eq(self, space, w_other):
+        if w_other.length() != 1:
+            return space.w_False
+        if self.value0 == w_other.value0:	#is it safe to assume all 1-tuples are specialised ?
+            return space.w_True
+        else:
+            return space.w_False
+
+    def hash(self, space):
+        mult = 1000003
+        x = 0x345678
+        z = 1
+        w_item = self.getitem(0)
+        y = space.int_w(space.hash(w_item))
+        x = (x ^ y) * mult
+        mult += 82520 + z + z
+        x += 97531
+        return space.wrap(intmask(x))
+
+class W_SpecialisedTupleObjectInt(W_SpecialisedTupleObject1):	#one integer element
+    def __init__(self, intval):
+        assert type(intval) == IntType#isinstance
+        self.intval = intval#intval
+
+    def tolist(self):
+        return [W_IntObject(self.intval)]
+
+    def getitem(self, index):
+        if index == 0:
+            return W_IntObject(self.intval)
+        raise IndexError
+
+    def setitem(self, index, w_item):
+        assert isinstance(w_item, W_IntObject)
+        if index == 0:
+            self.intval = w_item.intval
+            return
+        raise IndexError
+        
+class W_SpecialisedTupleObjectFloat(W_SpecialisedTupleObject1):	#one integer element
+    def __init__(self, floatval):
+        assert type(floatval) == FloatType
+        self.floatval = floatval
+
+    def tolist(self):
+        return [W_FloatObject(self.floatval)]
+
+    def getitem(self, index):
+        if index == 0:
+            return W_FloatObject(self.floatval)
+        raise IndexError
+
+    def setitem(self, index, w_item):
+        assert isinstance(w_item, W_FloatObject)
+        if index == 0:
+            self.floatval = w_item.floatval
+            return
+        raise IndexError
+        
+class W_SpecialisedTupleObjectString(W_SpecialisedTupleObject1):	#one integer element
+    def __init__(self, stringval):
+        assert type(stringval) == StringType
+        self.stringval = stringval
+
+    def tolist(self):
+        return [W_StringObject(self.stringval)]
+
+    def getitem(self, index):
+        if index == 0:
+            return W_StringObject(self.stringval)
+        raise IndexError
+
+    def setitem(self, index, w_item):
+        assert isinstance(w_item, W_StringObject)
+        if index == 0:
+            self.stringval = w_item._value # does  _value need to be private
+            return
+        raise IndexError
+        
+'''        
+        W_SpecialisedTupleObjectIntInt,	#two element tupes of int, float or string
+        W_SpecialisedTupleObjectIntFloat,
+        W_SpecialisedTupleObjectIntString,
+        W_SpecialisedTupleObjectFloatInt,
+        W_SpecialisedTupleObjectFloatFloat,
+        W_SpecialisedTupleObjectFloatString,
+        W_SpecialisedTupleObjectStringInt,
+        W_SpecialisedTupleObjectStringFloat,
+        W_SpecialisedTupleObjectStringString
+        
+'''
+registerimplementation(W_SpecialisedTupleObject)
+
+#---------
+def delegate_SpecialisedTuple2Tuple(space, w_specialised):
+    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"))
+
+# getitem__SpecialisedTuple_Slice removed
+# mul_specialisedtuple_times removed
+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)
+
+
+# mul__SpecialisedTuple_ANY removed
+# mul__ANY_SpecialisedTuple removed
+
+def eq__SpecialisedTuple_SpecialisedTuple(space, w_tuple1, w_tuple2):
+    return w_tuple1.eq(space, 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,118 @@
+from pypy.objspace.std.tupleobject import W_TupleObject
+from pypy.objspace.std.specialisedtupleobject import W_SpecialisedTupleObject
+from pypy.interpreter.error import OperationError
+from pypy.conftest import gettestobjspace
+from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject
+
+
+class TestW_SpecialisedTupleObject():
+
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withspecialisedtuple": True})
+
+    def test_isspecialisedtupleobject(self):
+        w_tuple = self.space.newtuple([self.space.wrap(1)])
+        assert isinstance(w_tuple, W_SpecialisedTupleObject)
+
+    def test_isnotspecialisedtupleobject(self):
+        w_tuple = self.space.newtuple([self.space.wrap({})])
+        assert not isinstance(w_tuple, W_SpecialisedTupleObject)
+
+    def test_isnotspecialised2tupleobject(self):
+        w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)])
+        assert not isinstance(w_tuple, W_SpecialisedTupleObject)
+        
+    def test_hash_against_normal_tuple(self):
+        normalspace = gettestobjspace(**{"objspace.std.withspecialisedtuple": False})
+        w_tuple = normalspace.newtuple([self.space.wrap(1)])
+
+        specialisedspace = gettestobjspace(**{"objspace.std.withspecialisedtuple": True})
+        w_specialisedtuple = specialisedspace.newtuple([self.space.wrap(1)])
+
+        assert isinstance(w_specialisedtuple, W_SpecialisedTupleObject)
+        assert isinstance(w_tuple, W_TupleObject)
+        assert not normalspace.is_true(normalspace.eq(w_tuple, w_specialisedtuple))
+        assert specialisedspace.is_true(specialisedspace.eq(w_tuple, w_specialisedtuple))
+        assert specialisedspace.is_true(specialisedspace.eq(normalspace.hash(w_tuple), specialisedspace.hash(w_specialisedtuple)))
+
+    def test_setitem(self):
+        w_specialisedtuple = self.space.newtuple([self.space.wrap(1)])
+        w_specialisedtuple.setitem(0, self.space.wrap(5))
+        list_w = w_specialisedtuple.tolist()
+        assert len(list_w) == 1
+        assert self.space.eq_w(list_w[0], self.space.wrap(5))        
+
+class AppTestW_SpecialisedTupleObject(AppTestW_TupleObject):
+
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withspecialisedtuple": True})
+        cls.w_isspecialised = cls.space.appexec([], """():
+            import __pypy__
+            def isspecialised(obj):
+                return "SpecialisedTuple" in __pypy__.internal_repr(obj)
+            return isspecialised
+        """)
+
+    def test_specialisedtuple(self):
+        assert self.isspecialised((42,))
+        assert self.isspecialised(('42',))
+        assert self.isspecialised((42.5,))
+        
+    def test_notspecialisedtuple(self):
+        assert not self.isspecialised((42,43))
+        
+    def test_slicing_to_specialised(self):
+        assert self.isspecialised((1, 2, 3)[0:1])   
+        assert self.isspecialised((1, '2', 1.3)[0:5:5])
+        assert self.isspecialised((1, '2', 1.3)[1:5:5])
+        assert self.isspecialised((1, '2', 1.3)[2:5:5])
+
+    def test_adding_to_specialised(self):
+        assert self.isspecialised(()+(2,))
+
+    def test_multiply_to_specialised(self):
+        assert self.isspecialised((1,)*1)
+
+    def test_slicing_from_specialised(self):
+        assert (1,)[0:1:1] == (1,)
+
+    def test_eq(self):
+        a = (1,)
+        b = (1,)
+        assert a == b
+
+        a = ('1',)
+        b = ('1',)
+        assert a == b
+
+        a = (1.1,)
+        b = (1.1,)
+        assert a == b
+
+        c = (1,3,2)
+        assert a != c
+        
+        d = (2)
+        assert a != d
+
+    def test_hash(self):
+        a = (1,)
+        b = (1,)
+        assert hash(a) == hash(b)
+
+        a = ('1',)
+        b = ('1',)
+        assert hash(a) == hash(b)
+
+        a = (1.1,)
+        b = (1.1,)
+        assert hash(a) == hash(b)
+
+        c = (2,)
+        assert hash(a) != hash(c)
+
+        
+        
+        
+        
+        
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
@@ -2,6 +2,8 @@
 from pypy.interpreter import gateway
 from pypy.objspace.std.register_all import register_all
 from pypy.objspace.std.stdtypedef import StdTypeDef, SMM
+from  types import IntType, FloatType, StringType
+
 
 def wraptuple(space, list_w):
     from pypy.objspace.std.tupleobject import W_TupleObject
@@ -12,6 +14,23 @@
     from pypy.objspace.std.smalltupleobject import W_SmallTupleObject6
     from pypy.objspace.std.smalltupleobject import W_SmallTupleObject7
     from pypy.objspace.std.smalltupleobject import W_SmallTupleObject8
+        
+    from pypy.objspace.std.specialisedtupleobject import W_SpecialisedTupleObjectInt	#one element tuples
+    from pypy.objspace.std.specialisedtupleobject import W_SpecialisedTupleObjectFloat
+    from pypy.objspace.std.specialisedtupleobject import W_SpecialisedTupleObjectString
+    from pypy.objspace.std.intobject import W_IntObject
+    from pypy.objspace.std.floatobject import W_FloatObject
+    from pypy.objspace.std.stringobject import W_StringObject
+    
+    if space.config.objspace.std.withspecialisedtuple:
+        if len(list_w) == 1:
+            if isinstance(list_w[0], W_IntObject):
+                 return W_SpecialisedTupleObjectInt(list_w[0].intval)
+            if isinstance(list_w[0], W_FloatObject):
+                 return W_SpecialisedTupleObjectFloat(list_w[0].floatval)
+            if isinstance(list_w[0], W_StringObject):
+                 return W_SpecialisedTupleObjectString(list_w[0]._value)
+
     if space.config.objspace.std.withsmalltuple:
         if len(list_w) == 2:
             return W_SmallTupleObject2(list_w)


More information about the pypy-commit mailing list