[pypy-svn] r54582 - in pypy/branch/gc-tweak/pypy/rpython: lltypesystem memory memory/test

arigo at codespeak.net arigo at codespeak.net
Fri May 9 12:10:12 CEST 2008


Author: arigo
Date: Fri May  9 12:10:11 2008
New Revision: 54582

Modified:
   pypy/branch/gc-tweak/pypy/rpython/lltypesystem/rdict.py
   pypy/branch/gc-tweak/pypy/rpython/memory/lldict.py
   pypy/branch/gc-tweak/pypy/rpython/memory/support.py
   pypy/branch/gc-tweak/pypy/rpython/memory/test/test_lldict.py
Log:
A copy_and_update() helper.


Modified: pypy/branch/gc-tweak/pypy/rpython/lltypesystem/rdict.py
==============================================================================
--- pypy/branch/gc-tweak/pypy/rpython/lltypesystem/rdict.py	(original)
+++ pypy/branch/gc-tweak/pypy/rpython/lltypesystem/rdict.py	Fri May  9 12:10:11 2008
@@ -601,7 +601,7 @@
     d = DICT.allocate()
     d.entries = DICT.entries.TO.allocate(n)
     d.num_items = 0
-    d.num_pristine_entries = DICT_INITSIZE
+    d.num_pristine_entries = n
     return d
 ll_newdict_size.oopspec = 'newdict()'
 

Modified: pypy/branch/gc-tweak/pypy/rpython/memory/lldict.py
==============================================================================
--- pypy/branch/gc-tweak/pypy/rpython/memory/lldict.py	(original)
+++ pypy/branch/gc-tweak/pypy/rpython/memory/lldict.py	Fri May  9 12:10:11 2008
@@ -13,8 +13,8 @@
     alloc_count += delta
 
 
-def newdict():
-    return rdict.ll_newdict(DICT)
+def newdict(length_estimate=0):
+    return rdict.ll_newdict_size(DICT, length_estimate)
 
 def dict_allocate():
     if not we_are_translated(): count_alloc(+1)
@@ -57,6 +57,15 @@
 def dict_add(d, key):
     rdict.ll_dict_setitem(d, key, llmemory.NULL)
 
+def dict_foreach(d, callback, arg):
+    entries = d.entries
+    i = len(entries) - 1
+    while i >= 0:
+        if dict_entry_valid(entries, i):
+            callback(entries[i].key, entries[i].value, arg)
+        i -= 1
+dict_foreach._annspecialcase_ = 'specialize:arg(1)'
+
 ENTRY = lltype.Struct('ENTRY', ('key', llmemory.Address),
                                ('value', llmemory.Address))
 ENTRIES = lltype.Array(ENTRY,
@@ -73,10 +82,12 @@
                      adtmeths = {
                          'allocate': dict_allocate,
                          'delete': dict_delete,
+                         'length': rdict.ll_dict_len,
                          'contains': rdict.ll_contains,
                          'setitem': rdict.ll_dict_setitem,
                          'get': dict_get,
                          'add': dict_add,
+                         'foreach': dict_foreach,
                          'keyhash': dict_keyhash,
                          'keyeq': None,
                      })

Modified: pypy/branch/gc-tweak/pypy/rpython/memory/support.py
==============================================================================
--- pypy/branch/gc-tweak/pypy/rpython/memory/support.py	(original)
+++ pypy/branch/gc-tweak/pypy/rpython/memory/support.py	Fri May  9 12:10:11 2008
@@ -111,6 +111,14 @@
                 cur = next
             free_non_gc_object(self)
 
+        def length(self):
+            chunk = self.chunk
+            count = self.used_in_last_chunk
+            while chunk:
+                chunk = chunk.next
+                count += chunk_size
+            return count
+
         def foreach(self, callback, arg):
             """Invoke 'callback(address, arg)' for all addresses in the stack.
             Typically, 'callback' is a bound method and 'arg' can be None.
@@ -126,7 +134,7 @@
         foreach._annspecialcase_ = 'specialize:arg(1)'
 
         def stack2dict(self):
-            result = AddressDict()
+            result = AddressDict(self.length())
             self.foreach(_add_in_dict, result)
             return result
 
@@ -205,26 +213,66 @@
 
 # ____________________________________________________________
 
-def AddressDict():
+def AddressDict(length_estimate=0):
     if we_are_translated():
         from pypy.rpython.memory import lldict
-        return lldict.newdict()
+        return lldict.newdict(length_estimate)
     else:
         return BasicAddressDict()
 
 class BasicAddressDict(object):
+
     def __init__(self):
         self.data = {}
+
     def _key(self, addr):
         return addr._fixup().ptr._obj
+
     def delete(self):
         pass
+
+    def length(self):
+        return len(self.data)
+
     def contains(self, keyaddr):
         return self._key(keyaddr) in self.data
+
     def get(self, keyaddr, default=llmemory.NULL):
         return self.data.get(self._key(keyaddr), default)
+
     def setitem(self, keyaddr, valueaddr):
         assert keyaddr
         self.data[self._key(keyaddr)] = valueaddr
+
     def add(self, keyaddr):
         self.setitem(keyaddr, llmemory.NULL)
+
+    def foreach(self, callback, arg):
+        """Invoke 'callback(key, value, arg)' for all items in the dict.
+        Typically, 'callback' is a bound method and 'arg' can be None."""
+        for key, value in self.data.iteritems():
+            callback(key, value, arg)
+
+
+def copy_and_update(dict, surviving, updated_address):
+    """Make a copy of 'dict' in which the keys are updated as follows:
+       * if surviving(key) returns False, the item is removed
+       * otherwise, updated_address(key) is inserted in the copy.
+    """
+    newdict = AddressDict
+    if not we_are_translated():
+        # when not translated, return a dict of the same kind as 'dict'
+        if not isinstance(dict, BasicAddressDict):
+            from pypy.rpython.memory.lldict import newdict
+    result = newdict(dict.length())
+    dict.foreach(_get_updater(surviving, updated_address), result)
+    return result
+copy_and_update._annspecialcase_ = 'specialize:arg(1,2)'
+
+def _get_updater(surviving, updated_address):
+    def callback(key, value, arg):
+        if surviving(key):
+            newkey = updated_address(key)
+            arg.setitem(newkey, value)
+    return callback
+_get_updater._annspecialcase_ = 'specialize:memo'

Modified: pypy/branch/gc-tweak/pypy/rpython/memory/test/test_lldict.py
==============================================================================
--- pypy/branch/gc-tweak/pypy/rpython/memory/test/test_lldict.py	(original)
+++ pypy/branch/gc-tweak/pypy/rpython/memory/test/test_lldict.py	Fri May  9 12:10:11 2008
@@ -1,6 +1,6 @@
 import random, sys
 from pypy.rpython.lltypesystem import lltype, llmemory
-from pypy.rpython.memory import lldict
+from pypy.rpython.memory import support, lldict
 
 
 class TestLLAddressDict:
@@ -20,9 +20,46 @@
         assert d.get(intaddr(42)) == llmemory.NULL
         assert d.get(intaddr(43)) == intaddr(44)
         assert d.get(intaddr(44)) == llmemory.NULL
+        assert d.length() == 2
         d.delete()
         assert lldict.alloc_count == 0
 
+    def test_foreach(self):
+        d = lldict.newdict()
+        for i in range(30):
+            d.setitem(intaddr(0x100 * i), intaddr(i))
+        result = []
+        d.foreach(lambda key, value, arg: result.append((key, value, arg)),
+                  "hello world")
+        assert len(result) == 30
+        seen = {}
+        for key, value, arg in result:
+            assert key.intval == 0x100 * value.intval
+            assert arg == "hello world"
+            seen[key.intval] = True
+        assert len(seen) == 30
+        d.delete()
+        assert lldict.alloc_count == 0
+
+    def test_copy_and_update(self):
+        d = lldict.newdict()
+        d.setitem(intaddr(41), intaddr(44))
+        d.setitem(intaddr(42), intaddr(45))
+        d.setitem(intaddr(43), intaddr(46))
+        def surviving(key):
+            return key.intval != 41
+        def updated_address(key):
+            return intaddr({42: 42, 43: 99}[key.intval])
+        d2 = support.copy_and_update(d, surviving, updated_address)
+        d.delete()
+        assert d2.length() == 2
+        assert d2.get(intaddr(41)) == llmemory.NULL
+        assert d2.get(intaddr(42)) == intaddr(45)
+        assert d2.get(intaddr(43)) == llmemory.NULL
+        assert d2.get(intaddr(99)) == intaddr(46)
+        d2.delete()
+        assert lldict.alloc_count == 0
+
     def test_random(self):
         for i in range(8) + range(8, 80, 10):
             examples = {}



More information about the Pypy-commit mailing list