[pypy-svn] r26071 - in pypy/dist/pypy: jit/timeshifter rpython rpython/lltypesystem rpython/ootypesystem rpython/ootypesystem/test rpython/test
antocuni at codespeak.net
antocuni at codespeak.net
Fri Apr 21 00:17:56 CEST 2006
Author: antocuni
Date: Fri Apr 21 00:17:24 2006
New Revision: 26071
Added:
pypy/dist/pypy/rpython/lltypesystem/rdict.py (contents, props changed)
pypy/dist/pypy/rpython/ootypesystem/rdict.py (contents, props changed)
pypy/dist/pypy/rpython/ootypesystem/test/test_oodict.py (contents, props changed)
Modified:
pypy/dist/pypy/jit/timeshifter/timeshift.py
pypy/dist/pypy/rpython/lltypesystem/rlist.py
pypy/dist/pypy/rpython/ootypesystem/ootype.py
pypy/dist/pypy/rpython/ootypesystem/rlist.py
pypy/dist/pypy/rpython/ootypesystem/test/test_oolist.py
pypy/dist/pypy/rpython/rbuiltin.py
pypy/dist/pypy/rpython/rdict.py
pypy/dist/pypy/rpython/rtyper.py
pypy/dist/pypy/rpython/test/test_rdict.py
pypy/dist/pypy/rpython/typesystem.py
Log:
- rdict has been made type-system depended. Almost all old code has
been moved to lltypesystem/rdict.py.
- some files has been fixed because they imported directly
rpython.rdict.
- a new Dict definition has been added to ootype.py.
Three tests in test_rtuple.py fail because by now ootypesystem lacks a
DictRepr, but they should automatically pass as soon as
ootypesystem.rdict.DictRepr will be added.
Modified: pypy/dist/pypy/jit/timeshifter/timeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/timeshift.py (original)
+++ pypy/dist/pypy/jit/timeshifter/timeshift.py Fri Apr 21 00:17:24 2006
@@ -5,8 +5,8 @@
from pypy.annotation import listdef, dictdef
from pypy.jit.timeshifter import rvalue
from pypy.jit.timeshifter.rtimeshift import JITState
-from pypy.rpython import rmodel, rdict, rgenop, annlowlevel
-from pypy.rpython.lltypesystem import rtuple, rlist
+from pypy.rpython import rmodel, rgenop, annlowlevel
+from pypy.rpython.lltypesystem import rtuple, rlist, rdict
from pypy.jit.timeshifter import rtimeshift
from pypy.jit.timeshifter.rtyper import HintRTyper, originalconcretetype
from pypy.jit.timeshifter.rtyper import GreenRepr, RedRepr, HintLowLevelOpList
Added: pypy/dist/pypy/rpython/lltypesystem/rdict.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/lltypesystem/rdict.py Fri Apr 21 00:17:24 2006
@@ -0,0 +1,773 @@
+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.lltypesystem import lltype
+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
+
+# ____________________________________________________________
+#
+# generic implementation of RPython dictionary, with parametric DICTKEY and
+# DICTVALUE types.
+#
+# XXX for immutable dicts, the array should be inlined and
+# num_pristine_entries 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
+# }
+#
+# struct dicttable {
+# int num_items;
+# int num_pristine_entries; # never used entries
+# Array *entries;
+# (Function DICTKEY, DICTKEY -> bool) *fnkeyeq;
+# (Function DICTKEY -> int) *fnkeyhash;
+# }
+#
+#
+
+class DictRepr(AbstractDictRepr):
+
+ def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue,
+ 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
+ if not isinstance(key_repr, rmodel.Repr): # not computed yet, done by setup()
+ assert callable(key_repr)
+ self._key_repr_computer = key_repr
+ else:
+ self.external_key_repr, self.key_repr = self.pickkeyrepr(key_repr)
+ if not isinstance(value_repr, rmodel.Repr): # not computed yet, done by setup()
+ assert callable(value_repr)
+ self._value_repr_computer = value_repr
+ else:
+ self.external_value_repr, self.value_repr = self.pickrepr(value_repr)
+ self.dictkey = dictkey
+ self.dictvalue = dictvalue
+ self.dict_cache = {}
+ self._custom_eq_hash_repr = custom_eq_hash
+ # setup() needs to be called to finish this initialization
+
+ def pickrepr(self, item_repr):
+ if self.custom_eq_hash:
+ return item_repr, item_repr
+ else:
+ return rmodel.externalvsinternal(self.rtyper, item_repr)
+
+ def pickkeyrepr(self, key_repr):
+ external, internal = self.pickrepr(key_repr)
+ if external != internal:
+ internal = external
+ while not self.rtyper.needs_hash_support(internal.classdef):
+ internal = internal.rbase
+ return external, internal
+
+ def compact_repr(self):
+ return 'DictR %s %s' % (self.key_repr.compact_repr(), self.value_repr.compact_repr())
+
+ def _setup_repr(self):
+ if 'key_repr' not in self.__dict__:
+ key_repr = self._key_repr_computer()
+ self.external_key_repr, self.key_repr = self.pickkeyrepr(key_repr)
+ 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 = {
+ '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 nullkeymarker:
+ entrymeths['everused'] = ll_everused_from_key
+ elif nullvaluemarker:
+ entrymeths['everused'] = ll_everused_from_value
+ else:
+ entryfields.append(("f_everused", lltype.Bool))
+ entrymeths['everused'] = ll_everused_from_flag
+
+ # * if the key or the value can also contain a "dummy" non-null
+ # marker, we use it for deleted entries.
+ rtyper = self.rtyper
+ dummy_obj = self.key_repr.get_ll_dummyval_obj(rtyper, s_key)
+ if dummy_obj:
+ entrymeths['dummy_obj'] = dummy_obj
+ 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
+ else:
+ dummy_obj = self.value_repr.get_ll_dummyval_obj(rtyper,
+ s_value)
+ if dummy_obj:
+ entrymeths['dummy_obj'] = dummy_obj
+ 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", adtmeths=entrymeths,
+ *entryfields)
+ self.DICTENTRYARRAY = lltype.GcArray(self.DICTENTRY)
+ fields = [ ("num_items", lltype.Signed),
+ ("num_pristine_entries", 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,
+ }
+ self.DICT.become(lltype.GcStruct("dicttable", adtmeths=adtmeths,
+ *fields))
+
+ def recast_value(self, llops, v):
+ return llops.convertvar(v, self.value_repr, self.external_value_repr)
+
+ def recast_key(self, llops, v):
+ return llops.convertvar(v, self.key_repr, self.external_key_repr)
+
+ def convert_const(self, dictobj):
+ # get object from bound dict methods
+ #dictobj = getattr(dictobj, '__self__', dictobj)
+ if dictobj is None:
+ return lltype.nullptr(self.DICT)
+ if not isinstance(dictobj, (dict, objectmodel.r_dict)):
+ raise TyperError("expected a dict: %r" % (dictobj,))
+ try:
+ key = Constant(dictobj)
+ return self.dict_cache[key]
+ except KeyError:
+ self.setup()
+ l_dict = ll_newdict_size(self.DICT, len(dictobj))
+ self.dict_cache[key] = l_dict
+ r_key = self.key_repr
+ r_value = self.value_repr
+ if isinstance(dictobj, objectmodel.r_dict):
+ if self.r_rdict_eqfn.lowleveltype != lltype.Void:
+ l_fn = self.r_rdict_eqfn.convert_const(dictobj.key_eq)
+ l_dict.fnkeyeq = l_fn
+ if self.r_rdict_hashfn.lowleveltype != lltype.Void:
+ l_fn = self.r_rdict_hashfn.convert_const(dictobj.key_hash)
+ l_dict.fnkeyhash = l_fn
+
+ for dictkeycontainer, dictvalue in dictobj._dict.items():
+ llkey = r_key.convert_const(dictkeycontainer.key)
+ llvalue = r_value.convert_const(dictvalue)
+ ll_dict_insertclean(l_dict, llkey, llvalue,
+ dictkeycontainer.hash)
+ return l_dict
+
+ else:
+ for dictkey, dictvalue in dictobj.items():
+ llkey = r_key.convert_const(dictkey)
+ llvalue = r_value.convert_const(dictvalue)
+ ll_dict_insertclean(l_dict, llkey, llvalue,
+ l_dict.keyhash(llkey))
+ return l_dict
+
+ def rtype_len(self, hop):
+ v_dict, = hop.inputargs(self)
+ return hop.gendirectcall(ll_dict_len, v_dict)
+
+ def rtype_is_true(self, hop):
+ v_dict, = hop.inputargs(self)
+ return hop.gendirectcall(ll_dict_is_true, v_dict)
+
+ def make_iterator_repr(self, *variant):
+ return DictIteratorRepr(self, *variant)
+
+ def rtype_method_get(self, hop):
+ v_dict, v_key, v_default = hop.inputargs(self, self.key_repr,
+ self.value_repr)
+ hop.exception_cannot_occur()
+ v_res = hop.gendirectcall(ll_get, v_dict, v_key, v_default)
+ return self.recast_value(hop.llops, v_res)
+
+ def rtype_method_setdefault(self, hop):
+ v_dict, v_key, v_default = hop.inputargs(self, self.key_repr,
+ self.value_repr)
+ hop.exception_cannot_occur()
+ v_res = hop.gendirectcall(ll_setdefault, v_dict, v_key, v_default)
+ return self.recast_value(hop.llops, v_res)
+
+ def rtype_method_copy(self, hop):
+ v_dict, = hop.inputargs(self)
+ hop.exception_cannot_occur()
+ return hop.gendirectcall(ll_copy, v_dict)
+
+ def rtype_method_update(self, hop):
+ v_dic1, v_dic2 = hop.inputargs(self, self)
+ hop.exception_cannot_occur()
+ return hop.gendirectcall(ll_update, v_dic1, v_dic2)
+
+ def _rtype_method_kvi(self, hop, spec):
+ v_dic, = hop.inputargs(self)
+ r_list = hop.r_result
+ v_func = hop.inputconst(lltype.Void, spec)
+ cLIST = hop.inputconst(lltype.Void, r_list.lowleveltype.TO)
+ hop.exception_cannot_occur()
+ return hop.gendirectcall(ll_kvi, v_dic, cLIST, v_func)
+
+ def rtype_method_keys(self, hop):
+ return self._rtype_method_kvi(hop, dum_keys)
+
+ def rtype_method_values(self, hop):
+ return self._rtype_method_kvi(hop, dum_values)
+
+ def rtype_method_items(self, hop):
+ return self._rtype_method_kvi(hop, dum_items)
+
+ 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)
+
+ def rtype_method_clear(self, hop):
+ v_dict, = hop.inputargs(self)
+ hop.exception_cannot_occur()
+ return hop.gendirectcall(ll_clear, v_dict)
+
+class __extend__(pairtype(DictRepr, rmodel.Repr)):
+
+ def rtype_getitem((r_dict, r_key), hop):
+ v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr)
+ if not r_dict.custom_eq_hash:
+ hop.has_implicit_exception(KeyError) # record that we know about it
+ hop.exception_is_here()
+ 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):
+ v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr)
+ if not r_dict.custom_eq_hash:
+ hop.has_implicit_exception(KeyError) # record that we know about it
+ hop.exception_is_here()
+ return hop.gendirectcall(ll_dict_delitem, v_dict, v_key)
+
+ def rtype_setitem((r_dict, r_key), hop):
+ v_dict, v_key, v_value = hop.inputargs(r_dict, r_dict.key_repr, r_dict.value_repr)
+ if r_dict.custom_eq_hash:
+ hop.exception_is_here()
+ else:
+ hop.exception_cannot_occur()
+ hop.gendirectcall(ll_dict_setitem, v_dict, v_key, v_value)
+
+ def rtype_contains((r_dict, r_key), hop):
+ v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr)
+ return hop.gendirectcall(ll_contains, v_dict, v_key)
+
+class __extend__(pairtype(DictRepr, DictRepr)):
+ def convert_from_to((r_dict1, r_dict2), v, llops):
+ # check that we don't convert from Dicts with
+ # different key/value types
+ if r_dict1.dictkey is None or r_dict2.dictkey is None:
+ return NotImplemented
+ if r_dict1.dictkey is not r_dict2.dictkey:
+ return NotImplemented
+ if r_dict1.dictvalue is None or r_dict2.dictvalue is None:
+ return NotImplemented
+ if r_dict1.dictvalue is not r_dict2.dictvalue:
+ return NotImplemented
+ return v
+
+# ____________________________________________________________
+#
+# Low-level methods. These can be run for testing, but are meant to
+# 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(entry):
+ return entry.f_everused
+
+def ll_everused_from_key(entry):
+ return bool(entry.key)
+
+def ll_everused_from_value(entry):
+ return bool(entry.value)
+
+def ll_valid_from_flag(entry):
+ return entry.f_valid
+
+def ll_mark_deleted_in_flag(entry):
+ entry.f_valid = False
+
+def ll_valid_from_key(entry):
+ ENTRY = lltype.typeOf(entry).TO
+ dummy = ENTRY.dummy_obj.ll_dummy_value
+ return entry.everused() and entry.key != dummy
+
+def ll_mark_deleted_in_key(entry):
+ ENTRY = lltype.typeOf(entry).TO
+ dummy = ENTRY.dummy_obj.ll_dummy_value
+ entry.key = dummy
+
+def ll_valid_from_value(entry):
+ ENTRY = lltype.typeOf(entry).TO
+ dummy = ENTRY.dummy_obj.ll_dummy_value
+ return entry.everused() and entry.value != dummy
+
+def ll_mark_deleted_in_value(entry):
+ ENTRY = lltype.typeOf(entry).TO
+ dummy = ENTRY.dummy_obj.ll_dummy_value
+ entry.value = dummy
+
+def ll_hash_from_cache(entry):
+ return entry.f_hash
+
+def ll_hash_recomputed(entry):
+ ENTRY = lltype.typeOf(entry).TO
+ return ENTRY.fasthashfn(entry.key)
+
+def ll_keyhash_custom(d, key):
+ DICT = lltype.typeOf(d).TO
+ return hlinvoke(DICT.r_rdict_hashfn, d.fnkeyhash, key)
+
+def ll_keyeq_custom(d, key1, key2):
+ 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
+
+def ll_dict_is_true(d):
+ # check if a dict is True, allowing for None
+ return bool(d) and d.num_items != 0
+
+def ll_dict_getitem(d, key):
+ entry = ll_dict_lookup(d, key, d.keyhash(key))
+ if entry.valid():
+ return entry.value
+ else:
+ raise KeyError
+
+def ll_dict_setitem(d, key, value):
+ hash = d.keyhash(key)
+ entry = ll_dict_lookup(d, key, hash)
+ everused = entry.everused()
+ valid = entry.valid()
+ # set up the new entry
+ ENTRY = lltype.typeOf(entry).TO
+ entry.value = value
+ if valid:
+ return
+ entry.key = key
+ if hasattr(ENTRY, 'f_hash'): entry.f_hash = hash
+ if hasattr(ENTRY, 'f_valid'): entry.f_valid = True
+ d.num_items += 1
+ if not everused:
+ if hasattr(ENTRY, 'f_everused'): entry.f_everused = True
+ d.num_pristine_entries -= 1
+ if d.num_pristine_entries <= len(d.entries) / 3:
+ ll_dict_resize(d)
+
+def ll_dict_insertclean(d, key, value, hash):
+ # Internal routine used by ll_dict_resize() to insert an item which is
+ # known to be absent from the dict. This routine also assumes that
+ # the dict contains no deleted entries. This routine has the advantage
+ # of never calling d.keyhash() and d.keyeq(), so it cannot call back
+ # to user code. ll_dict_insertclean() doesn't resize the dict, either.
+ entry = ll_dict_lookup_clean(d, hash)
+ ENTRY = lltype.typeOf(entry).TO
+ 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.num_pristine_entries -= 1
+
+def ll_dict_delitem(d, key):
+ entry = ll_dict_lookup(d, key, d.keyhash(key))
+ if not entry.valid():
+ raise KeyError
+ entry.mark_deleted()
+ d.num_items -= 1
+ # clear the key and the value if they are GC pointers
+ ENTRY = lltype.typeOf(entry).TO
+ if ENTRY.must_clear_key:
+ key = entry.key # careful about destructor side effects:
+ # keep key alive until entry.value has also
+ # been zeroed (if it must be)
+ entry.key = lltype.nullptr(ENTRY.key.TO)
+ if ENTRY.must_clear_value:
+ entry.value = lltype.nullptr(ENTRY.value.TO)
+ num_entries = len(d.entries)
+ if num_entries > DICT_INITSIZE and d.num_items < num_entries / 4:
+ ll_dict_resize(d)
+
+def ll_dict_resize(d):
+ old_entries = d.entries
+ old_size = len(old_entries)
+ # make a 'new_size' estimate and shrink it if there are many
+ # deleted entry markers
+ new_size = old_size * 2
+ while new_size > DICT_INITSIZE and d.num_items < new_size / 4:
+ new_size /= 2
+ d.entries = lltype.malloc(lltype.typeOf(old_entries).TO, new_size)
+ d.num_items = 0
+ d.num_pristine_entries = new_size
+ i = 0
+ while i < old_size:
+ entry = old_entries[i]
+ if entry.valid():
+ ll_dict_insertclean(d, entry.key, entry.value, entry.hash())
+ i += 1
+
+# ------- a port of CPython's dictobject.c's lookdict implementation -------
+PERTURB_SHIFT = 5
+
+def ll_dict_lookup(d, key, hash):
+ DICT = lltype.typeOf(d).TO
+ entries = d.entries
+ mask = len(entries) - 1
+ i = r_uint(hash & mask)
+ # do the first try before any looping
+ entry = entries[i]
+ if entry.valid():
+ checkingkey = entry.key
+ if checkingkey == key:
+ return entry # found the entry
+ if d.keyeq is not None and entry.hash() == hash:
+ # correct hash, maybe the key is e.g. a different pointer to
+ # an equal object
+ found = d.keyeq(checkingkey, key)
+ if DICT.paranoia:
+ if (entries != d.entries or
+ not entry.valid() or entry.key != checkingkey):
+ # the compare did major nasty stuff to the dict: start over
+ return ll_dict_lookup(d, key, hash)
+ if found:
+ return entry # found the entry
+ freeslot = lltype.nullptr(lltype.typeOf(entry).TO)
+ elif entry.everused():
+ freeslot = entry
+ else:
+ return entry # pristine entry -- lookup failed
+
+ # In the loop, a deleted entry (everused and not valid) is by far
+ # (factor of 100s) the least likely outcome, so test for that last.
+ perturb = r_uint(hash)
+ while 1:
+ i = ((i << 2) + i + perturb + 1) & mask
+ entry = entries[i]
+ if not entry.everused():
+ return freeslot or entry
+ elif entry.valid():
+ checkingkey = entry.key
+ if checkingkey == key:
+ return entry
+ if d.keyeq is not None and entry.hash() == hash:
+ # correct hash, maybe the key is e.g. a different pointer to
+ # an equal object
+ found = d.keyeq(checkingkey, key)
+ if DICT.paranoia:
+ if (entries != d.entries or
+ not entry.valid() or entry.key != checkingkey):
+ # the compare did major nasty stuff to the dict:
+ # start over
+ return ll_dict_lookup(d, key, hash)
+ if found:
+ return entry # found the entry
+ elif not freeslot:
+ freeslot = entry
+ perturb >>= PERTURB_SHIFT
+
+def ll_dict_lookup_clean(d, hash):
+ # a simplified version of ll_dict_lookup() which assumes that the
+ # key is new, and the dictionary doesn't contain deleted entries.
+ # It only find the next free slot for the given hash.
+ entries = d.entries
+ mask = len(entries) - 1
+ i = r_uint(hash & mask)
+ entry = entries[i]
+ perturb = r_uint(hash)
+ while entry.everused():
+ i = ((i << 2) + i + perturb + 1) & mask
+ entry = entries[i]
+ perturb >>= PERTURB_SHIFT
+ return entry
+
+# ____________________________________________________________
+#
+# Irregular operations.
+
+DICT_INITSIZE = 8
+
+def ll_newdict(DICT):
+ d = lltype.malloc(DICT)
+ d.entries = lltype.malloc(DICT.entries.TO, DICT_INITSIZE)
+ #d.num_items = 0 -- defaults
+ d.num_pristine_entries = DICT_INITSIZE
+ return d
+
+def ll_newdict_size(DICT, length_estimate):
+ length_estimate = (length_estimate // 2) * 3
+ n = DICT_INITSIZE
+ while n < length_estimate:
+ n *= 2
+ d = lltype.malloc(DICT)
+ d.entries = lltype.malloc(DICT.entries.TO, n)
+ #d.num_items = 0 -- defaults
+ d.num_pristine_entries = DICT_INITSIZE
+ return d
+
+
+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, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn,
+ r_dict.r_rdict_hashfn)
+ cDICT = hop.inputconst(lltype.Void, r_dict.DICT)
+ hop.exception_cannot_occur()
+ v_result = hop.gendirectcall(ll_newdict, cDICT)
+ if r_dict.r_rdict_eqfn.lowleveltype != lltype.Void:
+ cname = hop.inputconst(lltype.Void, 'fnkeyeq')
+ hop.genop('setfield', [v_result, cname, v_eqfn])
+ if r_dict.r_rdict_hashfn.lowleveltype != lltype.Void:
+ cname = hop.inputconst(lltype.Void, 'fnkeyhash')
+ hop.genop('setfield', [v_result, cname, v_hashfn])
+ return v_result
+
+# ____________________________________________________________
+#
+# Iteration.
+
+class DictIteratorRepr(rmodel.IteratorRepr):
+
+ def __init__(self, r_dict, variant="keys"):
+ self.r_dict = r_dict
+ self.variant = variant
+ self.lowleveltype = lltype.Ptr(lltype.GcStruct('dictiter',
+ ('dict', r_dict.lowleveltype),
+ ('index', lltype.Signed)))
+
+ 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)
+ iter.dict = d
+ iter.index = 0
+ return iter
+
+def ll_dictnext(iter, func, RETURNTYPE):
+ dict = iter.dict
+ if dict:
+ entries = dict.entries
+ index = iter.index
+ entries_len = len(entries)
+ while index < entries_len:
+ entry = entries[index]
+ index = index + 1
+ if entry.valid():
+ iter.index = index
+ if func is dum_items:
+ r = lltype.malloc(RETURNTYPE.TO)
+ r.item0 = recast(RETURNTYPE.TO.item0, entry.key)
+ r.item1 = recast(RETURNTYPE.TO.item1, entry.value)
+ return r
+ elif func is dum_keys:
+ return entry.key
+ elif func is dum_values:
+ return entry.value
+ # clear the reference to the dict and prevent restarts
+ iter.dict = lltype.nullptr(lltype.typeOf(iter).TO.dict.TO)
+ raise StopIteration
+
+# _____________________________________________________________
+# methods
+
+def ll_get(dict, key, default):
+ entry = ll_dict_lookup(dict, key, dict.keyhash(key))
+ if entry.valid():
+ return entry.value
+ else:
+ return default
+
+def ll_setdefault(dict, key, default):
+ entry = ll_dict_lookup(dict, key, dict.keyhash(key))
+ if entry.valid():
+ return entry.value
+ else:
+ ll_dict_setitem(dict, key, default)
+ return default
+
+def ll_copy(dict):
+ DICT = lltype.typeOf(dict).TO
+ dictsize = len(dict.entries)
+ d = lltype.malloc(DICT)
+ d.entries = lltype.malloc(DICT.entries.TO, dictsize)
+ d.num_items = dict.num_items
+ d.num_pristine_entries = dict.num_pristine_entries
+ if hasattr(DICT, 'fnkeyeq'): d.fnkeyeq = dict.fnkeyeq
+ if hasattr(DICT, 'fnkeyhash'): d.fnkeyhash = dict.fnkeyhash
+ i = 0
+ while i < dictsize:
+ d_entry = d.entries[i]
+ entry = dict.entries[i]
+ ENTRY = lltype.typeOf(entry).TO
+ d_entry.key = entry.key
+ if hasattr(ENTRY, 'f_valid'): d_entry.f_valid = entry.f_valid
+ if hasattr(ENTRY, 'f_everused'): d_entry.f_everused = entry.f_everused
+ d_entry.value = entry.value
+ if hasattr(ENTRY, 'f_hash'): d_entry.f_hash = entry.f_hash
+ i += 1
+ return d
+
+def ll_clear(d):
+ if len(d.entries) == d.num_pristine_entries == DICT_INITSIZE:
+ return
+ DICT = lltype.typeOf(d).TO
+ d.entries = lltype.malloc(DICT.entries.TO, DICT_INITSIZE)
+ d.num_items = 0
+ d.num_pristine_entries = DICT_INITSIZE
+
+def ll_update(dic1, dic2):
+ entries = dic2.entries
+ d2len = len(entries)
+ i = 0
+ while i < d2len:
+ entry = entries[i]
+ if entry.valid():
+ ll_dict_setitem(dic1, entry.key, entry.value)
+ i += 1
+
+# this is an implementation of keys(), values() and items()
+# in a single function.
+# note that by specialization on func, three different
+# and very efficient functions are created.
+
+def recast(P, v):
+ if isinstance(P, lltype.Ptr):
+ return lltype.cast_pointer(P, v)
+ else:
+ return v
+
+def ll_kvi(dic, LIST, func):
+ res = LIST.ll_newlist(dic.num_items)
+ entries = dic.entries
+ dlen = len(entries)
+ items = res.ll_items()
+ i = 0
+ p = 0
+ while i < dlen:
+ entry = entries[i]
+ if entry.valid():
+ ELEM = lltype.typeOf(items).TO.OF
+ if func is dum_items:
+ r = lltype.malloc(ELEM.TO)
+ r.item0 = recast(ELEM.TO.item0, entry.key)
+ r.item1 = recast(ELEM.TO.item1, entry.value)
+ items[p] = r
+ elif func is dum_keys:
+ items[p] = recast(ELEM, entry.key)
+ elif func is dum_values:
+ items[p] = recast(ELEM, entry.value)
+ p += 1
+ i += 1
+ return res
+
+def ll_contains(d, key):
+ entry = ll_dict_lookup(d, key, d.keyhash(key))
+ return entry.valid()
Modified: pypy/dist/pypy/rpython/lltypesystem/rlist.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/rlist.py (original)
+++ pypy/dist/pypy/rpython/lltypesystem/rlist.py Fri Apr 21 00:17:24 2006
@@ -49,15 +49,6 @@
self.listitem = listitem
self.list_cache = {}
# setup() needs to be called to finish this initialization
-## self.ll_concat = ll_concat
-## self.ll_extend = ll_extend
-## self.ll_listslice_startonly = ll_listslice_startonly
-## self.ll_listslice = ll_listslice
-## self.ll_listslice_minusone = ll_listslice_minusone
-## self.ll_listsetslice = ll_listsetslice
-## self.ll_listdelslice_startonly = ll_listdelslice_startonly
-## self.ll_listdelslice = ll_listdelslice
-## self.ll_listindex = ll_listindex
self.list_builder = ListBuilder()
def _setup_repr_final(self):
Modified: pypy/dist/pypy/rpython/ootypesystem/ootype.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/ootype.py (original)
+++ pypy/dist/pypy/rpython/ootypesystem/ootype.py Fri Apr 21 00:17:24 2006
@@ -181,8 +181,38 @@
StaticMethod.__init__(self, args, result)
-class List(OOType):
- # placeholders
+class BuiltinType(OOType):
+
+ def _setup_methods(self, generic_types):
+ methods = {}
+ for name, meth in self._GENERIC_METHODS.iteritems():
+ args = [generic_types.get(arg, arg) for arg in meth.ARGS]
+ result = generic_types.get(meth.RESULT, meth.RESULT)
+ methods[name] = Meth(args, result)
+ self._METHODS = frozendict(methods)
+
+ def _lookup(self, meth_name):
+ METH = self._METHODS.get(meth_name)
+ meth = None
+ if METH is not None:
+ cls = self._get_interp_class()
+ meth = _meth(METH, _name=meth_name, _callable=getattr(cls, meth_name))
+ return self, meth
+
+ def _example(self):
+ return new(self)
+
+ def _defl(self):
+ return self._null
+
+ def _get_interp_class(self):
+ raise NotImplementedError
+
+
+class List(BuiltinType):
+ # placeholders for types
+ # make sure that each derived class has his own SELFTYPE_T
+ # placeholder, because we want backends to distinguish that.
SELFTYPE_T = object()
ITEMTYPE_T = object()
@@ -209,9 +239,6 @@
"_ll_resize_ge": Meth([Signed], Void),
"_ll_resize_le": Meth([Signed], Void),
"_ll_resize": Meth([Signed], Void),
-## "append": Meth([self.ITEMTYPE_T], Void),
-## "extend": Meth([self.SELFTYPE_T], Void),
-## "remove_range": Meth([Signed, Signed], Void), # remove_range(start, count)
})
self._setup_methods(generic_types)
@@ -223,14 +250,6 @@
lst._ll_resize_ge(length)
return lst
- def _setup_methods(self, generic_types):
- methods = {}
- for name, meth in self._GENERIC_METHODS.iteritems():
- args = [generic_types.get(arg, arg) for arg in meth.ARGS]
- result = generic_types.get(meth.RESULT, meth.RESULT)
- methods[name] = Meth(args, result)
- self._METHODS = frozendict(methods)
-
# NB: We are expecting Lists of the same ITEMTYPE to compare/hash
# equal. We don't redefine __eq__/__hash__ since the implementations
# from LowLevelType work fine, especially in the face of recursive
@@ -241,19 +260,48 @@
return '%s(%s)' % (self.__class__.__name__,
saferecursive(str, "...")(self._ITEMTYPE))
- def _lookup(self, meth_name):
- METH = self._METHODS.get(meth_name)
- meth = None
- if METH is not None:
- meth = _meth(METH, _name=meth_name,
- _callable=getattr(_list, meth_name))
- return self, meth
+ def _get_interp_class(self):
+ return _list
- def _example(self):
- return new(self)
- def _defl(self):
- return self._null
+class Dict(BuiltinType):
+ # placeholders for types
+ SELFTYPE_T = object()
+ KEYTYPE_T = object()
+ VALUETYPE_T = object()
+
+ def __init__(self, KEYTYPE, VALUETYPE):
+ self._KEYTYPE = KEYTYPE
+ self._VALUETYPE = VALUETYPE
+ self._null = _null_dict(self)
+
+ generic_types = {
+ self.SELFTYPE_T: self,
+ self.KEYTYPE_T: KEYTYPE,
+ self.VALUETYPE_T: VALUETYPE
+ }
+
+ self._GENERIC_METHODS = frozendict({
+ "ll_length": Meth([], Signed),
+ "ll_getitem": Meth([self.KEYTYPE_T], self.VALUETYPE_T),
+ "ll_setitem": Meth([self.KEYTYPE_T, self.VALUETYPE_T], Void),
+ })
+
+ self._setup_methods(generic_types)
+
+ # NB: We are expecting Dicts of the same KEYTYPE, VALUETYPE to
+ # compare/hash equal. We don't redefine __eq__/__hash__ since the
+ # implementations from LowLevelType work fine, especially in the
+ # face of recursive data structures. But it is important to make
+ # sure that attributes of supposedly equal Dicts compare/hash
+ # equal.
+
+ def __str__(self):
+ return '%s(%s)' % (self.__class__.__name__,
+ saferecursive(str, "...")(self._KEYTYPE, self._VALUETYPE))
+
+ def _get_interp_class(self):
+ return _dict
class ForwardReference(OOType):
@@ -523,13 +571,7 @@
callb, checked_args = self.meth._checkargs(args)
return callb(self.inst, *checked_args)
-
-class _list(object):
-
- def __init__(self, LIST):
- self._TYPE = LIST
- self._list = []
-
+class _builtin_type(object):
def __getattribute__(self, name):
TYPE = object.__getattribute__(self, "_TYPE")
_, meth = TYPE._lookup(name)
@@ -537,6 +579,13 @@
return meth._bound(TYPE, self)
return object.__getattribute__(self, name)
+
+
+class _list(_builtin_type):
+
+ def __init__(self, LIST):
+ self._TYPE = LIST
+ self._list = []
# The following are implementations of the abstract list interface for
# use by the llinterpreter and ootype tests. There are NOT_RPYTHON
@@ -580,30 +629,40 @@
assert index >= 0
self._list[index] = item
-## def append(self, item):
-## # NOT_RPYTHON
-## assert typeOf(item) == self._TYPE._ITEMTYPE
-## self._list.append(item)
-
-## def extend(self, other):
-## # NOT_RPYTHON
-## assert typeOf(other) == typeOf(self)
-## self._list.extend(other._list)
-
-## def remove_range(self, start, count):
-## # NOT_RPYTHON
-## del self._list[start:start+count]
-
class _null_list(_null_mixin(_list), _list):
def __init__(self, LIST):
self.__dict__["_TYPE"] = LIST
+class _dict(object):
+ def __init__(self, DICT):
+ self._TYPE = DICT
+ self._dict = {}
+
+ def ll_length(self):
+ # NOT_RPYTHON
+ return len(self._dict)
+
+ def ll_getitem(self, key):
+ assert typeOf(key) == self._TYPE._KEYTYPE
+ return self._dict[key]
+
+ def ll_setitem(self, key, value):
+ assert typeOf(key) == self._TYPE._KEYTYPE
+ assert typeOf(value) == self._TYPE._VALUETYPE
+ self._dict[key] = value
+
+class _null_dict(_null_mixin(_dict), _dict):
+
+ def __init__(self, DICT):
+ self.__dict__["_TYPE"] = DICT
+
+
def new(TYPE):
if isinstance(TYPE, Instance):
return make_instance(TYPE)
- elif isinstance(TYPE, List):
- return _list(TYPE)
+ elif isinstance(TYPE, BuiltinType):
+ return TYPE._get_interp_class()(TYPE)
def runtimenew(class_):
assert isinstance(class_, _class)
Added: pypy/dist/pypy/rpython/ootypesystem/rdict.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/ootypesystem/rdict.py Fri Apr 21 00:17:24 2006
@@ -0,0 +1 @@
+# TODO
Modified: pypy/dist/pypy/rpython/ootypesystem/rlist.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/rlist.py (original)
+++ pypy/dist/pypy/rpython/ootypesystem/rlist.py Fri Apr 21 00:17:24 2006
@@ -25,15 +25,6 @@
self.lowleveltype = self.LIST
self.listitem = listitem
self.list_cache = {}
-## self.ll_concat = ll_concat
-## self.ll_extend = ll_extend
-## self.ll_listslice_startonly = ll_listslice_startonly
-## self.ll_listslice = ll_listslice
-## self.ll_listslice_minusone = ll_listslice_minusone
-## self.ll_listsetslice = ll_listsetslice
-## self.ll_listdelslice_startonly = ll_listdelslice_startonly
-## self.ll_listdelslice = ll_listdelslice
-## self.ll_listindex = ll_listindex
# setup() needs to be called to finish this initialization
def _setup_repr(self):
Added: pypy/dist/pypy/rpython/ootypesystem/test/test_oodict.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/rpython/ootypesystem/test/test_oodict.py Fri Apr 21 00:17:24 2006
@@ -0,0 +1,20 @@
+import py
+from pypy.rpython.test.test_llinterp import interpret
+from pypy.rpython.ootypesystem.ootype import Signed, Float, Dict, new, typeOf
+
+def test_new():
+ DT = Dict(Signed, Float)
+ d = new(DT)
+ assert typeOf(d) == DT
+
+def test_length():
+ DT = Dict(Signed, Float)
+ d = new(DT)
+ d.ll_setitem(42, 123.45)
+ assert d.ll_length() == 1
+
+def test_setitem_getitem():
+ DT = Dict(Signed, Float)
+ d = new(DT)
+ d.ll_setitem(42, 123.45)
+ assert d.ll_getitem(42) == 123.45
Modified: pypy/dist/pypy/rpython/ootypesystem/test/test_oolist.py
==============================================================================
--- pypy/dist/pypy/rpython/ootypesystem/test/test_oolist.py (original)
+++ pypy/dist/pypy/rpython/ootypesystem/test/test_oolist.py Fri Apr 21 00:17:24 2006
@@ -31,20 +31,6 @@
lst._ll_resize_le(10)
assert lst.ll_length() <= 10
-##def test_append():
-## LT = List(Signed)
-## l = new(LT)
-## l.append(1)
-## assert l.ll_length() == 1
-
-##def test_extend():
-## LT = List(Signed)
-## l1 = new(LT)
-## l2 = new(LT)
-## l1.append(1)
-## l2.append(2)
-## l1.extend(l2)
-## assert l1.ll_length() == 2
def test_setitem_getitem():
LT = List(Signed)
Modified: pypy/dist/pypy/rpython/rbuiltin.py
==============================================================================
--- pypy/dist/pypy/rpython/rbuiltin.py (original)
+++ pypy/dist/pypy/rpython/rbuiltin.py Fri Apr 21 00:17:24 2006
@@ -9,7 +9,7 @@
from pypy.rpython import rstr
from pypy.rpython import rptr
from pypy.rpython.robject import pyobj_repr
-from pypy.rpython.rdict import rtype_r_dict
+from pypy.rpython.lltypesystem.rdict import rtype_r_dict # TODO: typesystem?
from pypy.tool import sourcetools
from pypy.rpython import extregistry
Modified: pypy/dist/pypy/rpython/rdict.py
==============================================================================
--- pypy/dist/pypy/rpython/rdict.py (original)
+++ pypy/dist/pypy/rpython/rdict.py Fri Apr 21 00:17:24 2006
@@ -6,33 +6,8 @@
from pypy.rpython.objectmodel import hlinvoke
from pypy.rpython import robject
from pypy.rpython import objectmodel
-from pypy.rpython import rmodel
+from pypy.rpython.rmodel import Repr
-# ____________________________________________________________
-#
-# generic implementation of RPython dictionary, with parametric DICTKEY and
-# DICTVALUE types.
-#
-# XXX for immutable dicts, the array should be inlined and
-# num_pristine_entries 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
-# }
-#
-# struct dicttable {
-# int num_items;
-# int num_pristine_entries; # never used entries
-# Array *entries;
-# (Function DICTKEY, DICTKEY -> bool) *fnkeyeq;
-# (Function DICTKEY -> int) *fnkeyhash;
-# }
-#
-#
class __extend__(annmodel.SomeDict):
def rtyper_makerepr(self, rtyper):
@@ -49,572 +24,21 @@
rtyper.getrepr(dictkey.s_rdict_hashfn))
else:
custom_eq_hash = None
- return DictRepr(rtyper,
- lambda: rtyper.getrepr(s_key),
- lambda: rtyper.getrepr(s_value),
- dictkey,
- dictvalue,
- custom_eq_hash)
+ return rtyper.type_system.rdict.DictRepr(rtyper,
+ lambda: rtyper.getrepr(s_key),
+ lambda: rtyper.getrepr(s_value),
+ dictkey,
+ dictvalue,
+ custom_eq_hash)
def rtyper_makekey(self):
return (self.__class__, self.dictdef.dictkey, self.dictdef.dictvalue)
-class DictRepr(rmodel.Repr):
- def __init__(self, rtyper, key_repr, value_repr, dictkey, dictvalue,
- 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
- if not isinstance(key_repr, rmodel.Repr): # not computed yet, done by setup()
- assert callable(key_repr)
- self._key_repr_computer = key_repr
- else:
- self.external_key_repr, self.key_repr = self.pickkeyrepr(key_repr)
- if not isinstance(value_repr, rmodel.Repr): # not computed yet, done by setup()
- assert callable(value_repr)
- self._value_repr_computer = value_repr
- else:
- self.external_value_repr, self.value_repr = self.pickrepr(value_repr)
- self.dictkey = dictkey
- self.dictvalue = dictvalue
- self.dict_cache = {}
- self._custom_eq_hash_repr = custom_eq_hash
- # setup() needs to be called to finish this initialization
-
- def pickrepr(self, item_repr):
- if self.custom_eq_hash:
- return item_repr, item_repr
- else:
- return rmodel.externalvsinternal(self.rtyper, item_repr)
-
- def pickkeyrepr(self, key_repr):
- external, internal = self.pickrepr(key_repr)
- if external != internal:
- internal = external
- while not self.rtyper.needs_hash_support(internal.classdef):
- internal = internal.rbase
- return external, internal
-
- def compact_repr(self):
- return 'DictR %s %s' % (self.key_repr.compact_repr(), self.value_repr.compact_repr())
-
- def _setup_repr(self):
- if 'key_repr' not in self.__dict__:
- key_repr = self._key_repr_computer()
- self.external_key_repr, self.key_repr = self.pickkeyrepr(key_repr)
- 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 = {
- '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 nullkeymarker:
- entrymeths['everused'] = ll_everused_from_key
- elif nullvaluemarker:
- entrymeths['everused'] = ll_everused_from_value
- else:
- entryfields.append(("f_everused", lltype.Bool))
- entrymeths['everused'] = ll_everused_from_flag
-
- # * if the key or the value can also contain a "dummy" non-null
- # marker, we use it for deleted entries.
- rtyper = self.rtyper
- dummy_obj = self.key_repr.get_ll_dummyval_obj(rtyper, s_key)
- if dummy_obj:
- entrymeths['dummy_obj'] = dummy_obj
- 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
- else:
- dummy_obj = self.value_repr.get_ll_dummyval_obj(rtyper,
- s_value)
- if dummy_obj:
- entrymeths['dummy_obj'] = dummy_obj
- 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", adtmeths=entrymeths,
- *entryfields)
- self.DICTENTRYARRAY = lltype.GcArray(self.DICTENTRY)
- fields = [ ("num_items", lltype.Signed),
- ("num_pristine_entries", 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,
- }
- self.DICT.become(lltype.GcStruct("dicttable", adtmeths=adtmeths,
- *fields))
-
- def recast_value(self, llops, v):
- return llops.convertvar(v, self.value_repr, self.external_value_repr)
-
- def recast_key(self, llops, v):
- return llops.convertvar(v, self.key_repr, self.external_key_repr)
-
- def convert_const(self, dictobj):
- # get object from bound dict methods
- #dictobj = getattr(dictobj, '__self__', dictobj)
- if dictobj is None:
- return lltype.nullptr(self.DICT)
- if not isinstance(dictobj, (dict, objectmodel.r_dict)):
- raise TyperError("expected a dict: %r" % (dictobj,))
- try:
- key = Constant(dictobj)
- return self.dict_cache[key]
- except KeyError:
- self.setup()
- l_dict = ll_newdict_size(self.DICT, len(dictobj))
- self.dict_cache[key] = l_dict
- r_key = self.key_repr
- r_value = self.value_repr
- if isinstance(dictobj, objectmodel.r_dict):
- if self.r_rdict_eqfn.lowleveltype != lltype.Void:
- l_fn = self.r_rdict_eqfn.convert_const(dictobj.key_eq)
- l_dict.fnkeyeq = l_fn
- if self.r_rdict_hashfn.lowleveltype != lltype.Void:
- l_fn = self.r_rdict_hashfn.convert_const(dictobj.key_hash)
- l_dict.fnkeyhash = l_fn
-
- for dictkeycontainer, dictvalue in dictobj._dict.items():
- llkey = r_key.convert_const(dictkeycontainer.key)
- llvalue = r_value.convert_const(dictvalue)
- ll_dict_insertclean(l_dict, llkey, llvalue,
- dictkeycontainer.hash)
- return l_dict
-
- else:
- for dictkey, dictvalue in dictobj.items():
- llkey = r_key.convert_const(dictkey)
- llvalue = r_value.convert_const(dictvalue)
- ll_dict_insertclean(l_dict, llkey, llvalue,
- l_dict.keyhash(llkey))
- return l_dict
-
- def rtype_len(self, hop):
- v_dict, = hop.inputargs(self)
- return hop.gendirectcall(ll_dict_len, v_dict)
-
- def rtype_is_true(self, hop):
- v_dict, = hop.inputargs(self)
- return hop.gendirectcall(ll_dict_is_true, v_dict)
-
- def make_iterator_repr(self, *variant):
- return DictIteratorRepr(self, *variant)
-
- def rtype_method_get(self, hop):
- v_dict, v_key, v_default = hop.inputargs(self, self.key_repr,
- self.value_repr)
- hop.exception_cannot_occur()
- v_res = hop.gendirectcall(ll_get, v_dict, v_key, v_default)
- return self.recast_value(hop.llops, v_res)
-
- def rtype_method_setdefault(self, hop):
- v_dict, v_key, v_default = hop.inputargs(self, self.key_repr,
- self.value_repr)
- hop.exception_cannot_occur()
- v_res = hop.gendirectcall(ll_setdefault, v_dict, v_key, v_default)
- return self.recast_value(hop.llops, v_res)
-
- def rtype_method_copy(self, hop):
- v_dict, = hop.inputargs(self)
- hop.exception_cannot_occur()
- return hop.gendirectcall(ll_copy, v_dict)
-
- def rtype_method_update(self, hop):
- v_dic1, v_dic2 = hop.inputargs(self, self)
- hop.exception_cannot_occur()
- return hop.gendirectcall(ll_update, v_dic1, v_dic2)
-
- def _rtype_method_kvi(self, hop, spec):
- v_dic, = hop.inputargs(self)
- r_list = hop.r_result
- v_func = hop.inputconst(lltype.Void, spec)
- cLIST = hop.inputconst(lltype.Void, r_list.lowleveltype.TO)
- hop.exception_cannot_occur()
- return hop.gendirectcall(ll_kvi, v_dic, cLIST, v_func)
-
- def rtype_method_keys(self, hop):
- return self._rtype_method_kvi(hop, dum_keys)
-
- def rtype_method_values(self, hop):
- return self._rtype_method_kvi(hop, dum_values)
-
- def rtype_method_items(self, hop):
- return self._rtype_method_kvi(hop, dum_items)
-
- 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)
-
- def rtype_method_clear(self, hop):
- v_dict, = hop.inputargs(self)
- hop.exception_cannot_occur()
- return hop.gendirectcall(ll_clear, v_dict)
-
-class __extend__(pairtype(DictRepr, rmodel.Repr)):
-
- def rtype_getitem((r_dict, r_key), hop):
- v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr)
- if not r_dict.custom_eq_hash:
- hop.has_implicit_exception(KeyError) # record that we know about it
- hop.exception_is_here()
- 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):
- v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr)
- if not r_dict.custom_eq_hash:
- hop.has_implicit_exception(KeyError) # record that we know about it
- hop.exception_is_here()
- return hop.gendirectcall(ll_dict_delitem, v_dict, v_key)
-
- def rtype_setitem((r_dict, r_key), hop):
- v_dict, v_key, v_value = hop.inputargs(r_dict, r_dict.key_repr, r_dict.value_repr)
- if r_dict.custom_eq_hash:
- hop.exception_is_here()
- else:
- hop.exception_cannot_occur()
- hop.gendirectcall(ll_dict_setitem, v_dict, v_key, v_value)
-
- def rtype_contains((r_dict, r_key), hop):
- v_dict, v_key = hop.inputargs(r_dict, r_dict.key_repr)
- return hop.gendirectcall(ll_contains, v_dict, v_key)
-
-class __extend__(pairtype(DictRepr, DictRepr)):
- def convert_from_to((r_dict1, r_dict2), v, llops):
- # check that we don't convert from Dicts with
- # different key/value types
- if r_dict1.dictkey is None or r_dict2.dictkey is None:
- return NotImplemented
- if r_dict1.dictkey is not r_dict2.dictkey:
- return NotImplemented
- if r_dict1.dictvalue is None or r_dict2.dictvalue is None:
- return NotImplemented
- if r_dict1.dictvalue is not r_dict2.dictvalue:
- return NotImplemented
- return v
-
-# ____________________________________________________________
-#
-# Low-level methods. These can be run for testing, but are meant to
-# 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(entry):
- return entry.f_everused
-
-def ll_everused_from_key(entry):
- return bool(entry.key)
-
-def ll_everused_from_value(entry):
- return bool(entry.value)
+class AbstractDictRepr(Repr):
+ pass
-def ll_valid_from_flag(entry):
- return entry.f_valid
-
-def ll_mark_deleted_in_flag(entry):
- entry.f_valid = False
-
-def ll_valid_from_key(entry):
- ENTRY = lltype.typeOf(entry).TO
- dummy = ENTRY.dummy_obj.ll_dummy_value
- return entry.everused() and entry.key != dummy
-
-def ll_mark_deleted_in_key(entry):
- ENTRY = lltype.typeOf(entry).TO
- dummy = ENTRY.dummy_obj.ll_dummy_value
- entry.key = dummy
-
-def ll_valid_from_value(entry):
- ENTRY = lltype.typeOf(entry).TO
- dummy = ENTRY.dummy_obj.ll_dummy_value
- return entry.everused() and entry.value != dummy
-
-def ll_mark_deleted_in_value(entry):
- ENTRY = lltype.typeOf(entry).TO
- dummy = ENTRY.dummy_obj.ll_dummy_value
- entry.value = dummy
-
-def ll_hash_from_cache(entry):
- return entry.f_hash
-
-def ll_hash_recomputed(entry):
- ENTRY = lltype.typeOf(entry).TO
- return ENTRY.fasthashfn(entry.key)
-
-def ll_keyhash_custom(d, key):
- DICT = lltype.typeOf(d).TO
- return hlinvoke(DICT.r_rdict_hashfn, d.fnkeyhash, key)
-
-def ll_keyeq_custom(d, key1, key2):
- 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
-
-def ll_dict_is_true(d):
- # check if a dict is True, allowing for None
- return bool(d) and d.num_items != 0
-
-def ll_dict_getitem(d, key):
- entry = ll_dict_lookup(d, key, d.keyhash(key))
- if entry.valid():
- return entry.value
- else:
- raise KeyError
-
-def ll_dict_setitem(d, key, value):
- hash = d.keyhash(key)
- entry = ll_dict_lookup(d, key, hash)
- everused = entry.everused()
- valid = entry.valid()
- # set up the new entry
- ENTRY = lltype.typeOf(entry).TO
- entry.value = value
- if valid:
- return
- entry.key = key
- if hasattr(ENTRY, 'f_hash'): entry.f_hash = hash
- if hasattr(ENTRY, 'f_valid'): entry.f_valid = True
- d.num_items += 1
- if not everused:
- if hasattr(ENTRY, 'f_everused'): entry.f_everused = True
- d.num_pristine_entries -= 1
- if d.num_pristine_entries <= len(d.entries) / 3:
- ll_dict_resize(d)
-
-def ll_dict_insertclean(d, key, value, hash):
- # Internal routine used by ll_dict_resize() to insert an item which is
- # known to be absent from the dict. This routine also assumes that
- # the dict contains no deleted entries. This routine has the advantage
- # of never calling d.keyhash() and d.keyeq(), so it cannot call back
- # to user code. ll_dict_insertclean() doesn't resize the dict, either.
- entry = ll_dict_lookup_clean(d, hash)
- ENTRY = lltype.typeOf(entry).TO
- 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.num_pristine_entries -= 1
-
-def ll_dict_delitem(d, key):
- entry = ll_dict_lookup(d, key, d.keyhash(key))
- if not entry.valid():
- raise KeyError
- entry.mark_deleted()
- d.num_items -= 1
- # clear the key and the value if they are GC pointers
- ENTRY = lltype.typeOf(entry).TO
- if ENTRY.must_clear_key:
- key = entry.key # careful about destructor side effects:
- # keep key alive until entry.value has also
- # been zeroed (if it must be)
- entry.key = lltype.nullptr(ENTRY.key.TO)
- if ENTRY.must_clear_value:
- entry.value = lltype.nullptr(ENTRY.value.TO)
- num_entries = len(d.entries)
- if num_entries > DICT_INITSIZE and d.num_items < num_entries / 4:
- ll_dict_resize(d)
-
-def ll_dict_resize(d):
- old_entries = d.entries
- old_size = len(old_entries)
- # make a 'new_size' estimate and shrink it if there are many
- # deleted entry markers
- new_size = old_size * 2
- while new_size > DICT_INITSIZE and d.num_items < new_size / 4:
- new_size /= 2
- d.entries = lltype.malloc(lltype.typeOf(old_entries).TO, new_size)
- d.num_items = 0
- d.num_pristine_entries = new_size
- i = 0
- while i < old_size:
- entry = old_entries[i]
- if entry.valid():
- ll_dict_insertclean(d, entry.key, entry.value, entry.hash())
- i += 1
-
-# ------- a port of CPython's dictobject.c's lookdict implementation -------
-PERTURB_SHIFT = 5
-
-def ll_dict_lookup(d, key, hash):
- DICT = lltype.typeOf(d).TO
- entries = d.entries
- mask = len(entries) - 1
- i = r_uint(hash & mask)
- # do the first try before any looping
- entry = entries[i]
- if entry.valid():
- checkingkey = entry.key
- if checkingkey == key:
- return entry # found the entry
- if d.keyeq is not None and entry.hash() == hash:
- # correct hash, maybe the key is e.g. a different pointer to
- # an equal object
- found = d.keyeq(checkingkey, key)
- if DICT.paranoia:
- if (entries != d.entries or
- not entry.valid() or entry.key != checkingkey):
- # the compare did major nasty stuff to the dict: start over
- return ll_dict_lookup(d, key, hash)
- if found:
- return entry # found the entry
- freeslot = lltype.nullptr(lltype.typeOf(entry).TO)
- elif entry.everused():
- freeslot = entry
- else:
- return entry # pristine entry -- lookup failed
-
- # In the loop, a deleted entry (everused and not valid) is by far
- # (factor of 100s) the least likely outcome, so test for that last.
- perturb = r_uint(hash)
- while 1:
- i = ((i << 2) + i + perturb + 1) & mask
- entry = entries[i]
- if not entry.everused():
- return freeslot or entry
- elif entry.valid():
- checkingkey = entry.key
- if checkingkey == key:
- return entry
- if d.keyeq is not None and entry.hash() == hash:
- # correct hash, maybe the key is e.g. a different pointer to
- # an equal object
- found = d.keyeq(checkingkey, key)
- if DICT.paranoia:
- if (entries != d.entries or
- not entry.valid() or entry.key != checkingkey):
- # the compare did major nasty stuff to the dict:
- # start over
- return ll_dict_lookup(d, key, hash)
- if found:
- return entry # found the entry
- elif not freeslot:
- freeslot = entry
- perturb >>= PERTURB_SHIFT
-
-def ll_dict_lookup_clean(d, hash):
- # a simplified version of ll_dict_lookup() which assumes that the
- # key is new, and the dictionary doesn't contain deleted entries.
- # It only find the next free slot for the given hash.
- entries = d.entries
- mask = len(entries) - 1
- i = r_uint(hash & mask)
- entry = entries[i]
- perturb = r_uint(hash)
- while entry.everused():
- i = ((i << 2) + i + perturb + 1) & mask
- entry = entries[i]
- perturb >>= PERTURB_SHIFT
- return entry
-
-# ____________________________________________________________
-#
-# Irregular operations.
-
-DICT_INITSIZE = 8
-
-def ll_newdict(DICT):
- d = lltype.malloc(DICT)
- d.entries = lltype.malloc(DICT.entries.TO, DICT_INITSIZE)
- #d.num_items = 0 -- defaults
- d.num_pristine_entries = DICT_INITSIZE
- return d
-
-def ll_newdict_size(DICT, length_estimate):
- length_estimate = (length_estimate // 2) * 3
- n = DICT_INITSIZE
- while n < length_estimate:
- n *= 2
- d = lltype.malloc(DICT)
- d.entries = lltype.malloc(DICT.entries.TO, n)
- #d.num_items = 0 -- defaults
- d.num_pristine_entries = DICT_INITSIZE
- return d
def rtype_newdict(hop):
hop.inputargs() # no arguments expected
@@ -623,185 +47,5 @@
cdict = hop.inputconst(robject.pyobj_repr, dict)
return hop.genop('simple_call', [cdict], resulttype = robject.pyobj_repr)
cDICT = hop.inputconst(lltype.Void, r_dict.DICT)
- v_result = hop.gendirectcall(ll_newdict, cDICT)
- return v_result
-
-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, v_hashfn = hop.inputargs(r_dict.r_rdict_eqfn,
- r_dict.r_rdict_hashfn)
- cDICT = hop.inputconst(lltype.Void, r_dict.DICT)
- hop.exception_cannot_occur()
- v_result = hop.gendirectcall(ll_newdict, cDICT)
- if r_dict.r_rdict_eqfn.lowleveltype != lltype.Void:
- cname = hop.inputconst(lltype.Void, 'fnkeyeq')
- hop.genop('setfield', [v_result, cname, v_eqfn])
- if r_dict.r_rdict_hashfn.lowleveltype != lltype.Void:
- cname = hop.inputconst(lltype.Void, 'fnkeyhash')
- hop.genop('setfield', [v_result, cname, v_hashfn])
+ v_result = hop.gendirectcall(hop.rtyper.type_system.rdict.ll_newdict, cDICT)
return v_result
-
-# ____________________________________________________________
-#
-# Iteration.
-
-class DictIteratorRepr(rmodel.IteratorRepr):
-
- def __init__(self, r_dict, variant="keys"):
- self.r_dict = r_dict
- self.variant = variant
- self.lowleveltype = lltype.Ptr(lltype.GcStruct('dictiter',
- ('dict', r_dict.lowleveltype),
- ('index', lltype.Signed)))
-
- 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)
- iter.dict = d
- iter.index = 0
- return iter
-
-def ll_dictnext(iter, func, RETURNTYPE):
- dict = iter.dict
- if dict:
- entries = dict.entries
- index = iter.index
- entries_len = len(entries)
- while index < entries_len:
- entry = entries[index]
- index = index + 1
- if entry.valid():
- iter.index = index
- if func is dum_items:
- r = lltype.malloc(RETURNTYPE.TO)
- r.item0 = recast(RETURNTYPE.TO.item0, entry.key)
- r.item1 = recast(RETURNTYPE.TO.item1, entry.value)
- return r
- elif func is dum_keys:
- return entry.key
- elif func is dum_values:
- return entry.value
- # clear the reference to the dict and prevent restarts
- iter.dict = lltype.nullptr(lltype.typeOf(iter).TO.dict.TO)
- raise StopIteration
-
-# _____________________________________________________________
-# methods
-
-def ll_get(dict, key, default):
- entry = ll_dict_lookup(dict, key, dict.keyhash(key))
- if entry.valid():
- return entry.value
- else:
- return default
-
-def ll_setdefault(dict, key, default):
- entry = ll_dict_lookup(dict, key, dict.keyhash(key))
- if entry.valid():
- return entry.value
- else:
- ll_dict_setitem(dict, key, default)
- return default
-
-def ll_copy(dict):
- DICT = lltype.typeOf(dict).TO
- dictsize = len(dict.entries)
- d = lltype.malloc(DICT)
- d.entries = lltype.malloc(DICT.entries.TO, dictsize)
- d.num_items = dict.num_items
- d.num_pristine_entries = dict.num_pristine_entries
- if hasattr(DICT, 'fnkeyeq'): d.fnkeyeq = dict.fnkeyeq
- if hasattr(DICT, 'fnkeyhash'): d.fnkeyhash = dict.fnkeyhash
- i = 0
- while i < dictsize:
- d_entry = d.entries[i]
- entry = dict.entries[i]
- ENTRY = lltype.typeOf(entry).TO
- d_entry.key = entry.key
- if hasattr(ENTRY, 'f_valid'): d_entry.f_valid = entry.f_valid
- if hasattr(ENTRY, 'f_everused'): d_entry.f_everused = entry.f_everused
- d_entry.value = entry.value
- if hasattr(ENTRY, 'f_hash'): d_entry.f_hash = entry.f_hash
- i += 1
- return d
-
-def ll_clear(d):
- if len(d.entries) == d.num_pristine_entries == DICT_INITSIZE:
- return
- DICT = lltype.typeOf(d).TO
- d.entries = lltype.malloc(DICT.entries.TO, DICT_INITSIZE)
- d.num_items = 0
- d.num_pristine_entries = DICT_INITSIZE
-
-def ll_update(dic1, dic2):
- entries = dic2.entries
- d2len = len(entries)
- i = 0
- while i < d2len:
- entry = entries[i]
- if entry.valid():
- ll_dict_setitem(dic1, entry.key, entry.value)
- i += 1
-
-# this is an implementation of keys(), values() and items()
-# in a single function.
-# note that by specialization on func, three different
-# and very efficient functions are created.
-
-def recast(P, v):
- if isinstance(P, lltype.Ptr):
- return lltype.cast_pointer(P, v)
- else:
- return v
-
-def ll_kvi(dic, LIST, func):
- res = LIST.ll_newlist(dic.num_items)
- entries = dic.entries
- dlen = len(entries)
- items = res.ll_items()
- i = 0
- p = 0
- while i < dlen:
- entry = entries[i]
- if entry.valid():
- ELEM = lltype.typeOf(items).TO.OF
- if func is dum_items:
- r = lltype.malloc(ELEM.TO)
- r.item0 = recast(ELEM.TO.item0, entry.key)
- r.item1 = recast(ELEM.TO.item1, entry.value)
- items[p] = r
- elif func is dum_keys:
- items[p] = recast(ELEM, entry.key)
- elif func is dum_values:
- items[p] = recast(ELEM, entry.value)
- p += 1
- i += 1
- return res
-
-def ll_contains(d, key):
- entry = ll_dict_lookup(d, key, d.keyhash(key))
- return entry.valid()
Modified: pypy/dist/pypy/rpython/rtyper.py
==============================================================================
--- pypy/dist/pypy/rpython/rtyper.py (original)
+++ pypy/dist/pypy/rpython/rtyper.py Fri Apr 21 00:17:24 2006
@@ -522,7 +522,7 @@
return self.type_system.rlist.rtype_newlist(hop)
def translate_op_newdict(self, hop):
- return rdict.rtype_newdict(hop)
+ return self.type_system.rdict.rtype_newdict(hop)
def translate_op_alloc_and_set(self, hop):
return self.type_system.rlist.rtype_alloc_and_set(hop)
@@ -860,7 +860,7 @@
from pypy.rpython import robject
from pypy.rpython import rint, rbool, rfloat
from pypy.rpython import rslice, rrange
-from pypy.rpython import rstr, rdict
+from pypy.rpython import rstr, rdict
from pypy.rpython import rclass, rbuiltin, rpbc, rspecialcase
from pypy.rpython import rexternalobj
from pypy.rpython import rptr
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 Fri Apr 21 00:17:24 2006
@@ -1,7 +1,8 @@
from pypy.translator.translator import TranslationContext
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.test.test_llinterp import interpret
-from pypy.rpython import rstr, rint, rdict
+from pypy.rpython import rstr, rint
+from pypy.rpython.lltypesystem import rdict
import py
py.log.setconsumer("rtyper", py.log.STDOUT)
Modified: pypy/dist/pypy/rpython/typesystem.py
==============================================================================
--- pypy/dist/pypy/rpython/typesystem.py (original)
+++ pypy/dist/pypy/rpython/typesystem.py Fri Apr 21 00:17:24 2006
@@ -20,7 +20,7 @@
None, None, ['__doc__'])
except ImportError:
return None
- if name in ('rclass', 'rpbc', 'rbuiltin', 'rtuple', 'rlist', 'rslice',
+ if name in ('rclass', 'rpbc', 'rbuiltin', 'rtuple', 'rlist', 'rslice', 'rdict',
'exceptiondata'):
mod = load(name)
if mod is not None:
More information about the Pypy-commit
mailing list