Author: Maciej Fijalkowski <[email protected]>
Branch: rdict-experiments-2
Changeset: r59810:29353cb470d2
Date: 2013-01-06 17:51 +0200
http://bitbucket.org/pypy/pypy/changeset/29353cb470d2/

Log:    Branch to try rhettingers idea on dicts. So far fight with rtyper
        and try to factor out just enough to write tests.

diff --git a/pypy/rpython/lltypesystem/rdict.py 
b/pypy/rpython/lltypesystem/rdict.py
--- a/pypy/rpython/lltypesystem/rdict.py
+++ b/pypy/rpython/lltypesystem/rdict.py
@@ -1,9 +1,9 @@
 from pypy.tool.pairtype import pairtype
 from pypy.objspace.flow.model import Constant
 from pypy.rpython.rdict import (AbstractDictRepr, AbstractDictIteratorRepr,
-     rtype_newdict)
+                                rtype_newdict)
 from pypy.rpython.lltypesystem import lltype
-from pypy.rlib import objectmodel, jit
+from pypy.rlib import objectmodel, jit, rgc
 from pypy.rlib.debug import ll_assert
 from pypy.rlib.rarithmetic import r_uint, intmask, LONG_BIT
 from pypy.rpython import rmodel
@@ -13,18 +13,17 @@
 HIGHEST_BIT = intmask(1 << (LONG_BIT - 1))
 MASK = intmask(HIGHEST_BIT - 1)
 
+FREE = -2
+DELETED = -1
+
 # ____________________________________________________________
 #
 #  generic implementation of RPython dictionary, with parametric DICTKEY and
 #  DICTVALUE types.
 #
-#  XXX for immutable dicts, the array should be inlined and
-#      resize_counter and everused are not needed.
 #
 #    struct dictentry {
 #        DICTKEY key;
-#        bool f_valid;      # (optional) the entry is filled
-#        bool f_everused;   # (optional) the entry is or has ever been filled
 #        DICTVALUE value;
 #        int f_hash;        # (optional) key hash, if hard to recompute
 #    }
@@ -32,6 +31,7 @@
 #    struct dicttable {
 #        int num_items;
 #        int resize_counter;
+#        int *indexes; # note that this can be different int
 #        Array *entries;
 #        (Function DICTKEY, DICTKEY -> bool) *fnkeyeq;
 #        (Function DICTKEY -> int) *fnkeyhash;
@@ -39,14 +39,87 @@
 #
 #
 
+def get_ll_dict(DICTKEY, DICTVALUE, get_custom_eq_hash=None, DICT=None,
+                ll_fasthash_function=None, ll_hash_function=None,
+                ll_eq_function=None):
+    # get the actual DICT type. if DICT is None, it's created, otherwise
+    # forward reference is becoming DICT
+    if DICT is None:
+        DICT = lltype.GcForwardReference()
+    # compute the shape of the DICTENTRY structure
+    entryfields = []
+    entrymeths = {
+        'allocate': lltype.typeMethod(_ll_malloc_entries),
+        'must_clear_key':   (isinstance(DICTKEY, lltype.Ptr)
+                             and DICTKEY._needsgc()),
+        'must_clear_value': (isinstance(DICTVALUE, lltype.Ptr)
+                             and DICTVALUE._needsgc()),
+        }
+
+    # * the key
+    entryfields.append(("key", DICTKEY))
+
+    # * the value
+    entryfields.append(("value", DICTVALUE))
+
+    # * the hash, if needed
+    if get_custom_eq_hash is not None:
+        fasthashfn = None
+    else:
+        fasthashfn = ll_fasthash_function
+    if fasthashfn is None:
+        entryfields.append(("f_hash", lltype.Signed))
+        entrymeths['hash'] = ll_hash_from_cache
+    else:
+        entrymeths['hash'] = ll_hash_recomputed
+        entrymeths['fasthashfn'] = fasthashfn
+
+    # Build the lltype data structures
+    DICTENTRY = lltype.Struct("dictentry", *entryfields)
+    DICTENTRYARRAY = lltype.GcArray(DICTENTRY,
+                                    adtmeths=entrymeths)
+    fields = [("num_items", lltype.Signed),
+              ("resize_counter", lltype.Signed),
+              ("entries", lltype.Ptr(DICTENTRYARRAY)),
+              ("indexes", lltype.Ptr(lltype.GcArray(lltype.Signed)))]
+    if get_custom_eq_hash is not None:
+        r_rdict_eqfn, r_rdict_hashfn = get_custom_eq_hash()
+        fields.extend([ ("fnkeyeq", r_rdict_eqfn.lowleveltype),
+                        ("fnkeyhash", r_rdict_hashfn.lowleveltype) ])
+        adtmeths = {
+            'keyhash':        ll_keyhash_custom,
+            'keyeq':          ll_keyeq_custom,
+            'r_rdict_eqfn':   r_rdict_eqfn,
+            'r_rdict_hashfn': r_rdict_hashfn,
+            'paranoia':       True,
+            }
+    else:
+        # figure out which functions must be used to hash and compare
+        ll_keyhash = ll_hash_function
+        ll_keyeq = ll_eq_function  # can be None
+        ll_keyhash = lltype.staticAdtMethod(ll_keyhash)
+        if ll_keyeq is not None:
+            ll_keyeq = lltype.staticAdtMethod(ll_keyeq)
+        adtmeths = {
+            'keyhash':  ll_keyhash,
+            'keyeq':    ll_keyeq,
+            'paranoia': False,
+            }
+    adtmeths['KEY']   = DICTKEY
+    adtmeths['VALUE'] = DICTVALUE
+    adtmeths['allocate'] = lltype.typeMethod(_ll_malloc_dict)
+    DICT.become(lltype.GcStruct("dicttable", adtmeths=adtmeths,
+                                *fields))
+    return DICT
+
 class DictRepr(AbstractDictRepr):
 
     def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue,
-                 custom_eq_hash=None, force_non_null=False):
+                 custom_eq_hash=None):
         self.rtyper = rtyper
         self.DICT = lltype.GcForwardReference()
         self.lowleveltype = lltype.Ptr(self.DICT)
-        self.custom_eq_hash = custom_eq_hash is not None
+        self.custom_eq_hash = custom_eq_hash
         if not isinstance(key_repr, rmodel.Repr):  # not computed yet, done by 
setup()
             assert callable(key_repr)
             self._key_repr_computer = key_repr
@@ -60,8 +133,6 @@
         self.dictkey = dictkey
         self.dictvalue = dictvalue
         self.dict_cache = {}
-        self._custom_eq_hash_repr = custom_eq_hash
-        self.force_non_null = force_non_null
         # setup() needs to be called to finish this initialization
 
     def _externalvsinternal(self, rtyper, item_repr):
@@ -74,138 +145,9 @@
         if 'value_repr' not in self.__dict__:
             self.external_value_repr, self.value_repr = 
self.pickrepr(self._value_repr_computer())
         if isinstance(self.DICT, lltype.GcForwardReference):
-            self.DICTKEY = self.key_repr.lowleveltype
-            self.DICTVALUE = self.value_repr.lowleveltype
-
-            # compute the shape of the DICTENTRY structure
-            entryfields = []
-            entrymeths = {
-                'allocate': lltype.typeMethod(_ll_malloc_entries),
-                'delete': _ll_free_entries,
-                'must_clear_key':   (isinstance(self.DICTKEY, lltype.Ptr)
-                                     and self.DICTKEY._needsgc()),
-                'must_clear_value': (isinstance(self.DICTVALUE, lltype.Ptr)
-                                     and self.DICTVALUE._needsgc()),
-                }
-
-            # * the key
-            entryfields.append(("key", self.DICTKEY))
-
-            # * if NULL is not a valid ll value for the key or the value
-            #   field of the entry, it can be used as a marker for
-            #   never-used entries.  Otherwise, we need an explicit flag.
-            s_key   = self.dictkey.s_value
-            s_value = self.dictvalue.s_value
-            nullkeymarker = not self.key_repr.can_ll_be_null(s_key)
-            nullvaluemarker = not self.value_repr.can_ll_be_null(s_value)
-            if self.force_non_null:
-                if not nullkeymarker:
-                    rmodel.warning("%s can be null, but forcing non-null in 
dict key" % s_key)
-                    nullkeymarker = True
-                if not nullvaluemarker:
-                    rmodel.warning("%s can be null, but forcing non-null in 
dict value" % s_value)
-                    nullvaluemarker = True
-            dummykeyobj = self.key_repr.get_ll_dummyval_obj(self.rtyper,
-                                                            s_key)
-            dummyvalueobj = self.value_repr.get_ll_dummyval_obj(self.rtyper,
-                                                                s_value)
-
-            # * the state of the entry - trying to encode it as dummy objects
-            if nullkeymarker and dummykeyobj:
-                # all the state can be encoded in the key
-                entrymeths['everused'] = ll_everused_from_key
-                entrymeths['dummy_obj'] = dummykeyobj
-                entrymeths['valid'] = ll_valid_from_key
-                entrymeths['mark_deleted'] = ll_mark_deleted_in_key
-                # the key is overwritten by 'dummy' when the entry is deleted
-                entrymeths['must_clear_key'] = False
-
-            elif nullvaluemarker and dummyvalueobj:
-                # all the state can be encoded in the value
-                entrymeths['everused'] = ll_everused_from_value
-                entrymeths['dummy_obj'] = dummyvalueobj
-                entrymeths['valid'] = ll_valid_from_value
-                entrymeths['mark_deleted'] = ll_mark_deleted_in_value
-                # value is overwritten by 'dummy' when entry is deleted
-                entrymeths['must_clear_value'] = False
-
-            else:
-                # we need a flag to know if the entry was ever used
-                # (we cannot use a NULL as a marker for this, because
-                # the key and value will be reset to NULL to clear their
-                # reference)
-                entryfields.append(("f_everused", lltype.Bool))
-                entrymeths['everused'] = ll_everused_from_flag
-
-                # can we still rely on a dummy obj to mark deleted entries?
-                if dummykeyobj:
-                    entrymeths['dummy_obj'] = dummykeyobj
-                    entrymeths['valid'] = ll_valid_from_key
-                    entrymeths['mark_deleted'] = ll_mark_deleted_in_key
-                    # key is overwritten by 'dummy' when entry is deleted
-                    entrymeths['must_clear_key'] = False
-                elif dummyvalueobj:
-                    entrymeths['dummy_obj'] = dummyvalueobj
-                    entrymeths['valid'] = ll_valid_from_value
-                    entrymeths['mark_deleted'] = ll_mark_deleted_in_value
-                    # value is overwritten by 'dummy' when entry is deleted
-                    entrymeths['must_clear_value'] = False
-                else:
-                    entryfields.append(("f_valid", lltype.Bool))
-                    entrymeths['valid'] = ll_valid_from_flag
-                    entrymeths['mark_deleted'] = ll_mark_deleted_in_flag
-
-            # * the value
-            entryfields.append(("value", self.DICTVALUE))
-
-            # * the hash, if needed
-            if self.custom_eq_hash:
-                fasthashfn = None
-            else:
-                fasthashfn = self.key_repr.get_ll_fasthash_function()
-            if fasthashfn is None:
-                entryfields.append(("f_hash", lltype.Signed))
-                entrymeths['hash'] = ll_hash_from_cache
-            else:
-                entrymeths['hash'] = ll_hash_recomputed
-                entrymeths['fasthashfn'] = fasthashfn
-
-            # Build the lltype data structures
-            self.DICTENTRY = lltype.Struct("dictentry", *entryfields)
-            self.DICTENTRYARRAY = lltype.GcArray(self.DICTENTRY,
-                                                 adtmeths=entrymeths)
-            fields =          [ ("num_items", lltype.Signed),
-                                ("resize_counter", lltype.Signed),
-                                ("entries", lltype.Ptr(self.DICTENTRYARRAY)) ]
-            if self.custom_eq_hash:
-                self.r_rdict_eqfn, self.r_rdict_hashfn = 
self._custom_eq_hash_repr()
-                fields.extend([ ("fnkeyeq", self.r_rdict_eqfn.lowleveltype),
-                                ("fnkeyhash", 
self.r_rdict_hashfn.lowleveltype) ])
-                adtmeths = {
-                    'keyhash':        ll_keyhash_custom,
-                    'keyeq':          ll_keyeq_custom,
-                    'r_rdict_eqfn':   self.r_rdict_eqfn,
-                    'r_rdict_hashfn': self.r_rdict_hashfn,
-                    'paranoia':       True,
-                    }
-            else:
-                # figure out which functions must be used to hash and compare
-                ll_keyhash = self.key_repr.get_ll_hash_function()
-                ll_keyeq = self.key_repr.get_ll_eq_function()  # can be None
-                ll_keyhash = lltype.staticAdtMethod(ll_keyhash)
-                if ll_keyeq is not None:
-                    ll_keyeq = lltype.staticAdtMethod(ll_keyeq)
-                adtmeths = {
-                    'keyhash':  ll_keyhash,
-                    'keyeq':    ll_keyeq,
-                    'paranoia': False,
-                    }
-            adtmeths['KEY']   = self.DICTKEY
-            adtmeths['VALUE'] = self.DICTVALUE
-            adtmeths['allocate'] = lltype.typeMethod(_ll_malloc_dict)
-            self.DICT.become(lltype.GcStruct("dicttable", adtmeths=adtmeths,
-                                             *fields))
-
+            DICTKEY = self.key_repr.lowleveltype
+            DICTVALUE = self.value_repr.lowleveltype
+            xxx
 
     def convert_const(self, dictobj):
         from pypy.rpython.lltypesystem import llmemory
@@ -385,41 +327,6 @@
 #  be direct_call'ed from rtyped flow graphs, which means that they will
 #  get flowed and annotated, mostly with SomePtr.
 
-def ll_everused_from_flag(entries, i):
-    return entries[i].f_everused
-
-def ll_everused_from_key(entries, i):
-    return bool(entries[i].key)
-
-def ll_everused_from_value(entries, i):
-    return bool(entries[i].value)
-
-def ll_valid_from_flag(entries, i):
-    return entries[i].f_valid
-
-def ll_mark_deleted_in_flag(entries, i):
-    entries[i].f_valid = False
-
-def ll_valid_from_key(entries, i):
-    ENTRIES = lltype.typeOf(entries).TO
-    dummy = ENTRIES.dummy_obj.ll_dummy_value
-    return entries.everused(i) and entries[i].key != dummy
-
-def ll_mark_deleted_in_key(entries, i):
-    ENTRIES = lltype.typeOf(entries).TO
-    dummy = ENTRIES.dummy_obj.ll_dummy_value
-    entries[i].key = dummy
-
-def ll_valid_from_value(entries, i):
-    ENTRIES = lltype.typeOf(entries).TO
-    dummy = ENTRIES.dummy_obj.ll_dummy_value
-    return entries.everused(i) and entries[i].value != dummy
-
-def ll_mark_deleted_in_value(entries, i):
-    ENTRIES = lltype.typeOf(entries).TO
-    dummy = ENTRIES.dummy_obj.ll_dummy_value
-    entries[i].value = dummy
-
 def ll_hash_from_cache(entries, i):
     return entries[i].f_hash
 
@@ -464,15 +371,17 @@
     valid = (i & HIGHEST_BIT) == 0
     i = i & MASK
     ENTRY = lltype.typeOf(d.entries).TO.OF
-    entry = d.entries[i]
-    if not d.entries.everused(i):
+    index = d.indexes[i]
+    entry = d.entries[index]
+    if index == FREE:
         # a new entry that was never used before
         ll_assert(not valid, "valid but not everused")
         rc = d.resize_counter - 3
         if rc <= 0:       # if needed, resize the dict -- before the insertion
             ll_dict_resize(d)
-            i = ll_dict_lookup_clean(d, hash)  # then redo the lookup for 'key'
-            entry = d.entries[i]
+            index = ll_dict_lookup_clean(d, hash)
+            # then redo the lookup for 'key'
+            entry = d.entries[index]
             rc = d.resize_counter - 3
             ll_assert(rc > 0, "ll_dict_resize failed?")
         d.resize_counter = rc
@@ -496,12 +405,11 @@
     # to user code.  ll_dict_insertclean() doesn't resize the dict, either.
     i = ll_dict_lookup_clean(d, hash)
     ENTRY = lltype.typeOf(d.entries).TO.OF
-    entry = d.entries[i]
+    index = d.indexes[i]
+    entry = d.entries[index]
     entry.value = value
     entry.key = key
     if hasattr(ENTRY, 'f_hash'):     entry.f_hash = hash
-    if hasattr(ENTRY, 'f_valid'):    entry.f_valid = True
-    if hasattr(ENTRY, 'f_everused'): entry.f_everused = True
     d.num_items += 1
     d.resize_counter -= 3
 
@@ -513,6 +421,7 @@
 
 @jit.look_inside_iff(lambda d, i: jit.isvirtual(d) and jit.isconstant(i))
 def _ll_dict_del(d, i):
+    XXX
     d.entries.mark_deleted(i)
     d.num_items -= 1
     # clear the key and the value if they are GC pointers
@@ -539,7 +448,8 @@
 
 def ll_dict_resize(d):
     old_entries = d.entries
-    old_size = len(old_entries)
+    old_indexes = d.indexes
+    old_size = len(old_indexes)
     # make a 'new_size' estimate and shrink it if there are many
     # deleted entry markers.  See CPython for why it is a good idea to
     # quadruple the dictionary size as long as it's not too big.
@@ -550,17 +460,19 @@
     while new_size <= new_estimate:
         new_size *= 2
     #
-    d.entries = lltype.typeOf(old_entries).TO.allocate(new_size)
-    d.num_items = 0
+    new_item_size = new_size // 3 * 2 + 1
+    d.entries = lltype.typeOf(old_entries).TO.allocate(new_item_size)
+    d.indexes = lltype.malloc(lltype.typeOf(d).TO.indexes.TO, new_size)
+    d.num_items = len(old_entries)
     d.resize_counter = new_size * 2
     i = 0
+    indexes = d.indexes
     while i < old_size:
-        if old_entries.valid(i):
-            hash = old_entries.hash(i)
-            entry = old_entries[i]
-            ll_dict_insertclean(d, entry.key, entry.value, hash)
+        index = old_indexes[i]
+        if index >= 0:
+            indexes[ll_dict_lookup_clean(d, old_entries.hash(i))] = index
         i += 1
-    old_entries.delete()
+    rgc.ll_arraycopy(old_entries, d.entries, 0, 0, len(old_entries))
 ll_dict_resize.oopspec = 'dict.resize(d)'
 
 # ------- a port of CPython's dictobject.c's lookdict implementation -------
@@ -569,28 +481,30 @@
 @jit.look_inside_iff(lambda d, key, hash: jit.isvirtual(d) and 
jit.isconstant(key))
 def ll_dict_lookup(d, key, hash):
     entries = d.entries
+    indexes = d.indexes
     ENTRIES = lltype.typeOf(entries).TO
     direct_compare = not hasattr(ENTRIES, 'no_direct_compare')
     mask = len(entries) - 1
     i = hash & mask
     # do the first try before any looping
-    if entries.valid(i):
-        checkingkey = entries[i].key
+    index = indexes[i]
+    if index >= 0:
+        checkingkey = entries[index].key
         if direct_compare and checkingkey == key:
-            return i   # found the entry
-        if d.keyeq is not None and entries.hash(i) == hash:
+            return index   # found the entry
+        if d.keyeq is not None and entries.hash(index) == hash:
             # correct hash, maybe the key is e.g. a different pointer to
             # an equal object
             found = d.keyeq(checkingkey, key)
             if d.paranoia:
                 if (entries != d.entries or
-                    not entries.valid(i) or entries[i].key != checkingkey):
+                    not indexes[i] >= 0 or entries[index].key != checkingkey):
                     # the compare did major nasty stuff to the dict: start over
                     return ll_dict_lookup(d, key, hash)
             if found:
-                return i   # found the entry
+                return index   # found the entry
         freeslot = -1
-    elif entries.everused(i):
+    elif index == DELETED:
         freeslot = i
     else:
         return i | HIGHEST_BIT # pristine entry -- lookup failed
@@ -603,28 +517,30 @@
         i = r_uint(i)
         i = (i << 2) + i + perturb + 1
         i = intmask(i) & mask
+        index = indexes[i]
         # keep 'i' as a signed number here, to consistently pass signed
         # arguments to the small helper methods.
-        if not entries.everused(i):
+        if index == FREE:
             if freeslot == -1:
                 freeslot = i
             return freeslot | HIGHEST_BIT
-        elif entries.valid(i):
-            checkingkey = entries[i].key
+        elif index >= 0:
+            checkingkey = entries[index].key
             if direct_compare and checkingkey == key:
-                return i
-            if d.keyeq is not None and entries.hash(i) == hash:
+                return index
+            if d.keyeq is not None and entries.hash(index) == hash:
                 # correct hash, maybe the key is e.g. a different pointer to
                 # an equal object
                 found = d.keyeq(checkingkey, key)
                 if d.paranoia:
                     if (entries != d.entries or
-                        not entries.valid(i) or entries[i].key != checkingkey):
+                        not indexes[i] >= 0 or
+                        entries[index].key != checkingkey):
                         # the compare did major nasty stuff to the dict:
                         # start over
                         return ll_dict_lookup(d, key, hash)
                 if found:
-                    return i   # found the entry
+                    return index   # found the entry
         elif freeslot == -1:
             freeslot = i
         perturb >>= PERTURB_SHIFT
@@ -633,11 +549,11 @@
     # a simplified version of ll_dict_lookup() which assumes that the
     # key is new, and the dictionary doesn't contain deleted entries.
     # It only finds the next free slot for the given hash.
-    entries = d.entries
-    mask = len(entries) - 1
+    indexes = d.indexes
+    mask = len(indexes) - 1
     i = hash & mask
     perturb = r_uint(hash)
-    while entries.everused(i):
+    while i != FREE:
         i = r_uint(i)
         i = (i << 2) + i + perturb + 1
         i = intmask(i) & mask
@@ -649,10 +565,15 @@
 #  Irregular operations.
 
 DICT_INITSIZE = 8
+DICT_ITEMS_INITSIZE = 5
 
[email protected]_safe # we always unroll the small allocation
 def ll_newdict(DICT):
     d = DICT.allocate()
-    d.entries = DICT.entries.TO.allocate(DICT_INITSIZE)
+    d.indexes = lltype.malloc(DICT.indexes.TO, DICT_INITSIZE)
+    for i in range(DICT_INITSIZE):
+        d.indexes[i] = FREE
+    d.entries = DICT.entries.TO.allocate(DICT_ITEMS_INITSIZE)    
     d.num_items = 0
     d.resize_counter = DICT_INITSIZE * 2
     return d
@@ -662,8 +583,10 @@
     n = DICT_INITSIZE
     while n < length_estimate:
         n *= 2
+    items_size = n // 3 * 2 + 1
     d = DICT.allocate()
-    d.entries = DICT.entries.TO.allocate(n)
+    d.entries = DICT.entries.TO.allocate(items_size)
+    d.indexes = lltype.malloc(DICT.indexes.TO, n)
     d.num_items = 0
     d.resize_counter = n * 2
     return d
@@ -675,19 +598,14 @@
     return lltype.malloc(DICT)
 def _ll_malloc_entries(ENTRIES, n):
     return lltype.malloc(ENTRIES, n, zero=True)
-def _ll_free_entries(entries):
-    pass
 
 
-def rtype_r_dict(hop, i_force_non_null=None):
+def rtype_r_dict(hop):
     r_dict = hop.r_result
     if not r_dict.custom_eq_hash:
         raise TyperError("r_dict() call does not return an r_dict instance")
     v_eqfn = hop.inputarg(r_dict.r_rdict_eqfn, arg=0)
     v_hashfn = hop.inputarg(r_dict.r_rdict_hashfn, arg=1)
-    if i_force_non_null is not None:
-        assert i_force_non_null == 2
-        hop.inputarg(lltype.Void, arg=2)
     cDICT = hop.inputconst(lltype.Void, r_dict.DICT)
     hop.exception_cannot_occur()
     v_result = hop.gendirectcall(ll_newdict, cDICT)
@@ -780,6 +698,7 @@
         return default
 
 def ll_copy(dict):
+    xxx
     DICT = lltype.typeOf(dict).TO
     dictsize = len(dict.entries)
     d = DICT.allocate()
@@ -803,6 +722,7 @@
 ll_copy.oopspec = 'dict.copy(dict)'
 
 def ll_clear(d):
+    xxx
     if (len(d.entries) == DICT_INITSIZE and
         d.resize_counter == DICT_INITSIZE * 2):
         return
@@ -810,10 +730,10 @@
     d.entries = lltype.typeOf(old_entries).TO.allocate(DICT_INITSIZE)
     d.num_items = 0
     d.resize_counter = DICT_INITSIZE * 2
-    old_entries.delete()
 ll_clear.oopspec = 'dict.clear(d)'
 
 def ll_update(dic1, dic2):
+    xxx
     entries = dic2.entries
     d2len = len(entries)
     i = 0
diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py
--- a/pypy/rpython/test/test_rdict.py
+++ b/pypy/rpython/test/test_rdict.py
@@ -4,7 +4,9 @@
 from pypy.rpython.lltypesystem import rdict, rstr
 from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
 from pypy.rlib.objectmodel import r_dict
-from pypy.rlib.rarithmetic import r_int, r_uint, r_longlong, r_ulonglong
+from pypy.rlib.rarithmetic import r_int, r_uint, r_longlong, r_ulonglong,\
+     intmask
+from pypy.rpython.annlowlevel import llstr, hlstr
 
 import py
 py.log.setconsumer("rtyper", py.log.STDOUT)
@@ -22,6 +24,15 @@
         yield x
 
 
+class TestRDictDirect(object):
+    def test_dict_creation(self):
+        DICT = rdict.get_ll_dict(lltype.Ptr(rstr.STR), lltype.Signed,
+                                 
ll_fasthash_function=rstr.LLHelpers.ll_strhash,
+                                 ll_hash_function=rstr.LLHelpers.ll_strhash,
+                                 ll_eq_function=rstr.LLHelpers.ll_streq)
+        ll_d = rdict.ll_newdict(DICT)
+        rdict.ll_dict_setitem(ll_d, llstr("abc"), 13)
+
 class BaseTestRdict(BaseRtypingTest):
 
     def test_dict_creation(self):
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to