[pypy-svn] r26266 - in pypy/dist/pypy/rpython: . lltypesystem ootypesystem ootypesystem/test test

antocuni at codespeak.net antocuni at codespeak.net
Mon Apr 24 16:31:50 CEST 2006


Author: antocuni
Date: Mon Apr 24 16:31:40 2006
New Revision: 26266

Modified:
   pypy/dist/pypy/rpython/lltypesystem/rdict.py
   pypy/dist/pypy/rpython/ootypesystem/ootype.py
   pypy/dist/pypy/rpython/ootypesystem/rdict.py
   pypy/dist/pypy/rpython/ootypesystem/test/test_oodict.py
   pypy/dist/pypy/rpython/rdict.py
   pypy/dist/pypy/rpython/test/test_rdict.py
Log:
- The signature of ootype.Dict.ll_get has been changed

- some code has been factored out from lltypesystem.rlist.DictIteratorRepr 
  to rlist.AbstractDictIteratorRepr

- added support for iteration and iter* methods to ootypesystem.rdict.

The current implementation of itervalues() and iteritems() is far from
optimal because it does a dict lookup at every iteration. Probabily we
will need a refactoring to get rid of this.



Modified: pypy/dist/pypy/rpython/lltypesystem/rdict.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rdict.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/rdict.py	Mon Apr 24 16:31:40 2006
@@ -1,7 +1,8 @@
 from pypy.annotation.pairtype import pairtype
 from pypy.annotation import model as annmodel
 from pypy.objspace.flow.model import Constant
-from pypy.rpython.rdict import AbstractDictRepr, rtype_newdict
+from pypy.rpython.rdict import AbstractDictRepr, AbstractDictIteratorRepr,\
+     rtype_newdict, dum_variant, dum_keys, dum_values, dum_items
 from pypy.rpython.lltypesystem import lltype
 from pypy.rpython.rarithmetic import r_uint
 from pypy.rpython.objectmodel import hlinvoke
@@ -377,13 +378,6 @@
     DICT = lltype.typeOf(d).TO
     return hlinvoke(DICT.r_rdict_eqfn, d.fnkeyeq, key1, key2)
 
-def dum_keys(): pass
-def dum_values(): pass
-def dum_items():pass
-dum_variant = {"keys":   dum_keys,
-               "values": dum_values,
-               "items":  dum_items}
-
 def ll_dict_len(d):
     return d.num_items 
 
@@ -591,7 +585,7 @@
 #
 #  Iteration.
 
-class DictIteratorRepr(rmodel.IteratorRepr):
+class DictIteratorRepr(AbstractDictIteratorRepr):
 
     def __init__(self, r_dict, variant="keys"):
         self.r_dict = r_dict
@@ -599,29 +593,9 @@
         self.lowleveltype = lltype.Ptr(lltype.GcStruct('dictiter',
                                          ('dict', r_dict.lowleveltype),
                                          ('index', lltype.Signed)))
+        self.ll_dictiter = ll_dictiter
+        self.ll_dictnext = ll_dictnext
 
-    def newiter(self, hop):
-        v_dict, = hop.inputargs(self.r_dict)
-        citerptr = hop.inputconst(lltype.Void, self.lowleveltype)
-        return hop.gendirectcall(ll_dictiter, citerptr, v_dict)
-
-    def rtype_next(self, hop):
-        variant = self.variant
-        v_iter, = hop.inputargs(self)
-        v_func = hop.inputconst(lltype.Void, dum_variant[self.variant])
-        if variant in ('keys', 'values'):
-            c1 = hop.inputconst(lltype.Void, None)
-        else:
-            c1 = hop.inputconst(lltype.Void, hop.r_result.lowleveltype)
-        hop.has_implicit_exception(StopIteration) # record that we know about it
-        hop.exception_is_here()
-        v = hop.gendirectcall(ll_dictnext, v_iter, v_func, c1)
-        if variant == 'keys':
-            return self.r_dict.recast_key(hop.llops, v)
-        elif variant == 'values':
-            return self.r_dict.recast_value(hop.llops, v)
-        else:
-            return v
 
 def ll_dictiter(ITERPTR, d):
     iter = lltype.malloc(ITERPTR.TO)

Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/ootype.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/ootype.py	Mon Apr 24 16:31:40 2006
@@ -297,7 +297,7 @@
 
         self._GENERIC_METHODS = frozendict({
             "ll_length": Meth([], Signed),
-            "ll_get": Meth([self.KEYTYPE_T, self.VALUETYPE_T], self.VALUETYPE_T), # ll_get(key, default)
+            "ll_get": Meth([self.KEYTYPE_T], self.VALUETYPE_T),
             "ll_set": Meth([self.KEYTYPE_T, self.VALUETYPE_T], Void),
             "ll_remove": Meth([self.KEYTYPE_T], Bool), # return False is key was not present
             "ll_contains": Meth([self.KEYTYPE_T], Bool),
@@ -664,11 +664,11 @@
         # NOT_RPYTHON
         return len(self._dict)
 
-    def ll_get(self, key, default):
+    def ll_get(self, key):
         # NOT_RPYTHON        
         assert typeOf(key) == self._TYPE._KEYTYPE
-        assert typeOf(key) == self._TYPE._VALUETYPE
-        return self._dict.get(key, default)
+        assert key in self._dict
+        return self._dict[key]
 
     def ll_set(self, key, value):
         # NOT_RPYTHON        

Modified: pypy/dist/pypy/rpython/ootypesystem/rdict.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/rdict.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/rdict.py	Mon Apr 24 16:31:40 2006
@@ -1,17 +1,17 @@
 from pypy.annotation.pairtype import pairtype
 from pypy.annotation import model as annmodel
 from pypy.objspace.flow.model import Constant
-from pypy.rpython.rdict import AbstractDictRepr, rtype_newdict
+from pypy.rpython.rdict import AbstractDictRepr, AbstractDictIteratorRepr,\
+     rtype_newdict, dum_variant, dum_keys, dum_values, dum_items
 from pypy.rpython.ootypesystem import ootype
 from pypy.rpython.ootypesystem.rlist import ll_newlist
+from pypy.rpython.ootypesystem.riterable import iterator_type
 from pypy.rpython.rarithmetic import r_uint
 from pypy.rpython.objectmodel import hlinvoke
 from pypy.rpython import robject
 from pypy.rpython import objectmodel
 from pypy.rpython import rmodel
 
-def dum_values(): pass
-def dum_items():pass
 
 class DictRepr(AbstractDictRepr):
     def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue,
@@ -65,6 +65,9 @@
         return hop.genop("oosend", [c_name] + v_args,
                 resulttype=hop.r_result.lowleveltype)
 
+    def make_iterator_repr(self, *variant):
+        return DictIteratorRepr(self, *variant)
+
     def rtype_len(self, hop):
         v_dict, = hop.inputargs(self)
         return self.send_message(hop, 'll_length')
@@ -77,8 +80,7 @@
         v_dict, v_key, v_default = hop.inputargs(self, self.key_repr,
                                                  self.value_repr)
         hop.exception_cannot_occur()
-        v_res = self.send_message(hop, 'll_get')
-        #v_res = hop.gendirectcall(ll_get, v_dict, v_key, v_default)
+        v_res = hop.gendirectcall(ll_dict_get, v_dict, v_key, v_default)
         return self.recast_value(hop.llops, v_res)
 
     def rtype_method_setdefault(self, hop):
@@ -103,14 +105,19 @@
         r_list = hop.r_result
         cLIST = hop.inputconst(ootype.Void, r_list.lowleveltype)
         c_func = hop.inputconst(ootype.Void, spec)        
-        c_dummy_default = hop.inputconst(self.value_repr.lowleveltype,
-                                         self.value_repr.ll_dummy_value)
-        return hop.gendirectcall(ll_dict_values_items, v_dict, cLIST, c_func, c_dummy_default)
-
-##    def rtype_method_items(self, hop):
-##        v_dict, = hop.inputargs(self)
-##        return hop.gendirectcall(ll_dict_items, v_dict)
+        return hop.gendirectcall(ll_dict_values_items, v_dict, cLIST, c_func)
 
+    def rtype_method_iterkeys(self, hop):
+        hop.exception_cannot_occur()
+        return DictIteratorRepr(self, "keys").newiter(hop)
+
+    def rtype_method_itervalues(self, hop):
+        hop.exception_cannot_occur()
+        return DictIteratorRepr(self, "values").newiter(hop)
+
+    def rtype_method_iteritems(self, hop):
+        hop.exception_cannot_occur()
+        return DictIteratorRepr(self, "items").newiter(hop)
 
 
 class __extend__(pairtype(DictRepr, rmodel.Repr)): 
@@ -120,8 +127,7 @@
         if not r_dict.custom_eq_hash: # TODO: why only in this case?
             hop.has_implicit_exception(KeyError)   # record that we know about it
         hop.exception_is_here()
-        c_dummy_default = hop.inputconst(r_dict.value_repr.lowleveltype, r_dict.value_repr.ll_dummy_value)
-        v_res = hop.gendirectcall(ll_dict_getitem, v_dict, v_key, c_dummy_default)
+        v_res = hop.gendirectcall(ll_dict_getitem, v_dict, v_key)
         return r_dict.recast_value(hop.llops, v_res)
 
     def rtype_delitem((r_dict, r_key), hop):
@@ -153,10 +159,10 @@
     # check if a dict is True, allowing for None
     return bool(d) and d.ll_length() != 0
 
-def ll_dict_getitem(d, key, dummy_default):
+def ll_dict_getitem(d, key):
     # TODO: this is inefficient because it does two lookups
     if d.ll_contains(key):
-        return d.ll_get(key, dummy_default) # dummy_default is never returned
+        return d.ll_get(key)
     else:
         raise KeyError
 
@@ -164,21 +170,28 @@
     if not d.ll_remove(key):
         raise KeyError
 
+def ll_dict_get(d, key, default):
+    # TODO: this is inefficient because it does two lookups
+    if d.ll_contains(key):
+        return d.ll_get(key)
+    else:
+        return default
+
 def ll_dict_setdefault(d, key, default):
     try:
-        return ll_dict_getitem(d, key, default)
+        return ll_dict_getitem(d, key)
     except KeyError:
         d.ll_set(key, default)
         return default
 
-def ll_dict_values_items(d, LIST, func, dummy_default):
+def ll_dict_values_items(d, LIST, func):
     keys = d.ll_keys()
     length = keys.ll_length()
     result = ll_newlist(LIST, length)
     i = 0
     while i < length:
         key = keys.ll_getitem_fast(i)
-        value = d.ll_get(key, dummy_default) # dummy_default is never returned
+        value = d.ll_get(key)
         if func is dum_items:
             r = ootype.new(LIST._ITEMTYPE)
             r.item0 = key   # TODO: do we need casting?
@@ -189,3 +202,45 @@
 
         i += 1
     return result
+
+
+# ____________________________________________________________
+#
+#  Iteration.
+
+class DictIteratorRepr(AbstractDictIteratorRepr):
+
+    def __init__(self, r_dict, variant="keys"):
+        self.r_dict = r_dict
+        self.variant = variant
+        self.lowleveltype = iterator_type(r_dict, r_dict.key_repr)
+        self.ll_dictiter = ll_dictiter
+        self.ll_dictnext = ll_dictnext
+
+def ll_dictiter(ITER, d):
+    iter = ootype.new(ITER)
+    iter.iterable = d
+    iter.index = 0
+    return iter
+
+# TODO: this is very inefficient for values and items because it does
+# a dict lookup at every iteration. Need to be refactored.
+def ll_dictnext(iter, func, RETURNTYPE):
+    d = iter.iterable
+    keys = d.ll_keys()
+    index = iter.index
+    if index >= keys.ll_length():
+        raise StopIteration
+    iter.index = index + 1
+
+    key = keys.ll_getitem_fast(index)
+    if func is dum_keys:
+        return key
+    elif func is dum_values:
+        return d.ll_get(key)
+    elif func is dum_items:
+        res = ootype.new(RETURNTYPE)
+        res.item0 = key
+        res.item1 = d.ll_get(key)
+        return res
+        

Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_oodict.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/test/test_oodict.py	(original)
+++ pypy/dist/pypy/rpython/ootypesystem/test/test_oodict.py	Mon Apr 24 16:31:40 2006
@@ -17,5 +17,4 @@
     DT = Dict(Signed, Float)
     d = new(DT)
     d.ll_set(42, 123.45)
-    assert d.ll_get(42, 0.0) == 123.45
-    assert d.ll_get(43, 0.0) == 0.0
+    assert d.ll_get(42) == 123.45

Modified: pypy/dist/pypy/rpython/rdict.py
==============================================================================
--- pypy/dist/pypy/rpython/rdict.py	(original)
+++ pypy/dist/pypy/rpython/rdict.py	Mon Apr 24 16:31:40 2006
@@ -8,6 +8,13 @@
 from pypy.rpython import objectmodel
 from pypy.rpython import rmodel
 
+def dum_keys(): pass
+def dum_values(): pass
+def dum_items():pass
+dum_variant = {"keys":   dum_keys,
+               "values": dum_values,
+               "items":  dum_items}
+
 
 class __extend__(annmodel.SomeDict):
     def rtyper_makerepr(self, rtyper):
@@ -71,3 +78,29 @@
     cDICT = hop.inputconst(lltype.Void, r_dict.DICT)
     v_result = hop.gendirectcall(hop.rtyper.type_system.rdict.ll_newdict, cDICT)
     return v_result
+
+
+class AbstractDictIteratorRepr(rmodel.IteratorRepr):
+    def newiter(self, hop):
+        v_dict, = hop.inputargs(self.r_dict)
+        citerptr = hop.inputconst(lltype.Void, self.lowleveltype)
+        return hop.gendirectcall(self.ll_dictiter, citerptr, v_dict)
+
+    def rtype_next(self, hop):
+        variant = self.variant
+        v_iter, = hop.inputargs(self)
+        v_func = hop.inputconst(lltype.Void, dum_variant[self.variant])
+        if variant in ('keys', 'values'):
+            c1 = hop.inputconst(lltype.Void, None)
+        else:
+            c1 = hop.inputconst(lltype.Void, hop.r_result.lowleveltype)
+        hop.has_implicit_exception(StopIteration) # record that we know about it
+        hop.exception_is_here()
+        v = hop.gendirectcall(self.ll_dictnext, v_iter, v_func, c1)
+        if variant == 'keys':
+            return self.r_dict.recast_key(hop.llops, v)
+        elif variant == 'values':
+            return self.r_dict.recast_value(hop.llops, v)
+        else:
+            return v
+    

Modified: pypy/dist/pypy/rpython/test/test_rdict.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_rdict.py	(original)
+++ pypy/dist/pypy/rpython/test/test_rdict.py	Mon Apr 24 16:31:40 2006
@@ -819,3 +819,41 @@
         res = [self.ll_to_tuple(item, 2) for item in res]
         assert res == [(42, 43), (13, 14)] or res == [(13, 14), (42, 43)]
 
+    def test_iteration(self):
+        def func(x, y):
+            d = {x: x+1, y: y+1}
+            tot = 0
+            for key in  d:
+                tot += key
+            return tot
+        assert self.interpret(func, [42, 13]) == 55
+
+    def test_iterkeys(self):
+        def func(x, y):
+            d = {x: x+1, y: y+1}
+            tot = 0
+            for key in  d.iterkeys():
+                tot += key
+            return tot
+        assert self.interpret(func, [42, 13]) == 55
+
+    def test_itervalues(self):
+        def func(x, y):
+            d = {x: x+1, y: y+1}
+            tot = 0
+            for value in  d.itervalues():
+                tot += value
+            return tot
+        assert self.interpret(func, [42, 13]) == 57
+
+    def test_iteritems(self):
+        def func(x, y):
+            d = {x: x+1, y: y+1}
+            tot1 = 0
+            tot2 = 0
+            for key, value in  d.iteritems():
+                tot1 += key
+                tot2 += value
+            return tot1, tot2
+        res = self.ll_to_tuple(self.interpret(func, [42, 13]), 2)
+        assert res == (55, 57)



More information about the Pypy-commit mailing list