[pypy-svn] r32151 - in pypy/branch/rdict-index-based/pypy/rpython: lltypesystem test
mwh at codespeak.net
mwh at codespeak.net
Mon Sep 11 14:48:20 CEST 2006
Author: mwh
Date: Mon Sep 11 14:48:19 2006
New Revision: 32151
Modified:
pypy/branch/rdict-index-based/pypy/rpython/lltypesystem/rdict.py
pypy/branch/rdict-index-based/pypy/rpython/test/test_rdict.py
Log:
move all the adt methods onto the dictionary rather than the entry.
haven't made much attempt to make the code look natural, but it's not too bad
apart from ll_dict_resize which is really really horrible.
Modified: pypy/branch/rdict-index-based/pypy/rpython/lltypesystem/rdict.py
==============================================================================
--- pypy/branch/rdict-index-based/pypy/rpython/lltypesystem/rdict.py (original)
+++ pypy/branch/rdict-index-based/pypy/rpython/lltypesystem/rdict.py Mon Sep 11 14:48:19 2006
@@ -93,6 +93,7 @@
nullkeymarker = not self.key_repr.can_ll_be_null(s_key)
nullvaluemarker = not self.value_repr.can_ll_be_null(s_value)
+ entrymeths['entry_has_f_everused'] = 0
if nullkeymarker:
entrymeths['everused'] = ll_everused_from_key
elif nullvaluemarker:
@@ -100,11 +101,13 @@
else:
entryfields.append(("f_everused", lltype.Bool))
entrymeths['everused'] = ll_everused_from_flag
+ entrymeths['entry_has_f_everused'] = 1
# * 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)
+ entrymeths['entry_has_f_valid'] = 0
if dummy_obj:
entrymeths['dummy_obj'] = dummy_obj
entrymeths['valid'] = ll_valid_from_key
@@ -122,6 +125,7 @@
entrymeths['must_clear_value'] = False
else:
entryfields.append(("f_valid", lltype.Bool))
+ entrymeths['entry_has_f_valid'] = 1
entrymeths['valid'] = ll_valid_from_flag
entrymeths['mark_deleted'] = ll_mark_deleted_in_flag
@@ -133,15 +137,18 @@
fasthashfn = None
else:
fasthashfn = self.key_repr.get_ll_fasthash_function()
+
+ entrymeths['entry_has_f_hash'] = 0
if fasthashfn is None:
entryfields.append(("f_hash", lltype.Signed))
+ entrymeths['entry_has_f_hash'] = 1
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,
+ self.DICTENTRY = lltype.Struct("dictentry", #adtmeths=entrymeths,
*entryfields)
self.DICTENTRYARRAY = lltype.GcArray(self.DICTENTRY)
fields = [ ("num_items", lltype.Signed),
@@ -170,6 +177,7 @@
'keyeq': ll_keyeq,
'paranoia': False,
}
+ adtmeths.update(entrymeths)
self.DICT.become(lltype.GcStruct("dicttable", adtmeths=adtmeths,
*fields))
@@ -331,47 +339,47 @@
# 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_flag(d, i):
+ return d.entries[i].f_everused
-def ll_everused_from_key(entry):
- return bool(entry.key)
+def ll_everused_from_key(d, i):
+ return bool(d.entries[i].key)
-def ll_everused_from_value(entry):
- return bool(entry.value)
+def ll_everused_from_value(d, i):
+ return bool(d.entries[i].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_valid_from_flag(d, i):
+ return d.entries[i].f_valid
+
+def ll_mark_deleted_in_flag(d, i):
+ d.entries[i].f_valid = False
+
+def ll_valid_from_key(d, i):
+ DICT = lltype.typeOf(d).TO
+ dummy = DICT.dummy_obj.ll_dummy_value
+ return d.everused(i) and d.entries[i].key != dummy
+
+def ll_mark_deleted_in_key(d, i):
+ DICT = lltype.typeOf(d).TO
+ dummy = DICT.dummy_obj.ll_dummy_value
+ d.entries[i].key = dummy
+
+def ll_valid_from_value(d, i):
+ DICT = lltype.typeOf(d).TO
+ dummy = DICT.dummy_obj.ll_dummy_value
+ return d.everused(i) and d.entries[i].value != dummy
+
+def ll_mark_deleted_in_value(d, i):
+ DICT = lltype.typeOf(d).TO
+ dummy = DICT.dummy_obj.ll_dummy_value
+ d.entries[i].value = dummy
+
+def ll_hash_from_cache(d, i):
+ return d.entries[i].f_hash
+
+def ll_hash_recomputed(d, i):
+ DICT = lltype.typeOf(d).TO
+ return DICT.fasthashfn(d.entries[i].key)
def ll_keyhash_custom(d, key):
DICT = lltype.typeOf(d).TO
@@ -389,28 +397,29 @@
return bool(d) and d.num_items != 0
def ll_dict_getitem(d, key):
- entry = d.entries[ll_dict_lookup(d, key, d.keyhash(key))]
- if entry.valid():
- return entry.value
+ i = ll_dict_lookup(d, key, d.keyhash(key))
+ if d.valid(i):
+ return d.entries[i].value
else:
raise KeyError
def ll_dict_setitem(d, key, value):
hash = d.keyhash(key)
- entry = d.entries[ll_dict_lookup(d, key, hash)]
- everused = entry.everused()
- valid = entry.valid()
+ i = ll_dict_lookup(d, key, hash)
+ entry = d.entries[i]
+ everused = d.everused(i)
+ valid = d.valid(i)
# set up the new entry
- ENTRY = lltype.typeOf(entry).TO
+ DICT = lltype.typeOf(d).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
+ if DICT.entry_has_f_hash: entry.f_hash = hash
+ if DICT.entry_has_f_valid: entry.f_valid = True
d.num_items += 1
if not everused:
- if hasattr(ENTRY, 'f_everused'): entry.f_everused = True
+ if DICT.entry_has_f_everused: entry.f_everused = True
d.num_pristine_entries -= 1
if d.num_pristine_entries <= len(d.entries) / 3:
ll_dict_resize(d)
@@ -422,52 +431,76 @@
# 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 = d.entries[ll_dict_lookup_clean(d, hash)]
- ENTRY = lltype.typeOf(entry).TO
+ DICT = lltype.typeOf(d).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
+ if DICT.entry_has_f_hash: entry.f_hash = hash
+ if DICT.entry_has_f_valid: entry.f_valid = True
+ if DICT.entry_has_f_everused: entry.f_everused = True
d.num_items += 1
d.num_pristine_entries -= 1
def ll_dict_delitem(d, key):
- entry = d.entries[ll_dict_lookup(d, key, d.keyhash(key))]
- if not entry.valid():
+ i = ll_dict_lookup(d, key, d.keyhash(key))
+ if not d.valid(i):
raise KeyError
- entry.mark_deleted()
+ entry = d.entries[i]
+ d.mark_deleted(i)
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:
+ DICT = lltype.typeOf(d).TO
+ if DICT.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)
+ entry.key = lltype.nullptr(DICT.entries.OF.key.TO)
+ if DICT.must_clear_value:
+ entry.value = lltype.nullptr(DICT.entries.OF.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)
+ 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, zero=True)
- d.num_items = 0
- d.num_pristine_entries = new_size
+ new_entries = lltype.malloc(lltype.typeOf(d).TO.entries.TO, new_size, zero=True)
+ new_num_items = 0
+ new_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())
+ entry = d.entries[i]
+ if d.valid(i):
+
+ # AAAAAAAAAAA
+ hash = d.hash(i)
+
+ old_entries = d.entries
+ old_num_items = d.num_items
+ old_num_pristine_entries = d.num_pristine_entries
+ d.entries = new_entries
+ d.num_items = new_num_items
+ d.num_pristine_entries = new_num_pristine_entries
+
+ ll_dict_insertclean(d, entry.key, entry.value, hash)
+
+ new_entries = d.entries
+ new_num_items = d.num_items
+ new_num_pristine_entries = d.num_pristine_entries
+ d.entries = old_entries
+ d.num_items = old_num_items
+ d.num_pristine_entries = old_num_pristine_entries
+
i += 1
+ d.entries = new_entries
+ d.num_items = new_num_items
+ d.num_pristine_entries = new_num_pristine_entries
+
# ------- a port of CPython's dictobject.c's lookdict implementation -------
PERTURB_SHIFT = 5
@@ -480,22 +513,22 @@
entry = entries[i]
found_freeslot = False
freeslot_index = r_uint(0)
- if entry.valid():
+ if d.valid(i):
checkingkey = entry.key
if checkingkey == key:
return i # found the entry
- if d.keyeq is not None and entry.hash() == hash:
+ if d.keyeq is not None and d.hash(i) == 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):
+ not d.valid(i) 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 i # found the entry
- elif entry.everused():
+ elif d.everused(i):
freeslot_index = i
found_freeslot = True
else:
@@ -507,22 +540,22 @@
while 1:
i = ((i << 2) + i + perturb + 1) & mask
entry = entries[i]
- if not entry.everused():
+ if not d.everused(i):
if found_freeslot:
return freeslot_index
else:
return i
- elif entry.valid():
+ elif d.valid(i):
checkingkey = entry.key
if checkingkey == key:
return i
- if d.keyeq is not None and entry.hash() == hash:
+ if d.keyeq is not None and d.hash(i) == 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):
+ not d.valid(i) or entry.key != checkingkey):
# the compare did major nasty stuff to the dict:
# start over
return ll_dict_lookup(d, key, hash)
@@ -542,7 +575,7 @@
i = r_uint(hash & mask)
entry = entries[i]
perturb = r_uint(hash)
- while entry.everused():
+ while d.everused(i):
i = ((i << 2) + i + perturb + 1) & mask
entry = entries[i]
perturb >>= PERTURB_SHIFT
@@ -620,8 +653,9 @@
entries_len = len(entries)
while index < entries_len:
entry = entries[index]
+ i = index
index = index + 1
- if entry.valid():
+ if dict.valid(i):
iter.index = index
if RETURNTYPE is lltype.Void:
return None
@@ -631,6 +665,9 @@
r.item1 = recast(RETURNTYPE.TO.item1, entry.value)
return r
elif func is dum_keys:
+ from pypy.rpython.lltypesystem.lloperation import llop
+ from pypy.rpython.lltypesystem.lltype import Void
+ llop.debug_print(Void, entry.key)
return entry.key
elif func is dum_values:
return entry.value
@@ -642,16 +679,16 @@
# methods
def ll_get(dict, key, default):
- entry = dict.entries[ll_dict_lookup(dict, key, dict.keyhash(key))]
- if entry.valid():
- return entry.value
+ i = ll_dict_lookup(dict, key, dict.keyhash(key))
+ if dict.valid(i):
+ return dict.entries[i].value
else:
return default
def ll_setdefault(dict, key, default):
- entry = dict.entries[ll_dict_lookup(dict, key, dict.keyhash(key))]
- if entry.valid():
- return entry.value
+ i = ll_dict_lookup(dict, key, dict.keyhash(key))
+ if dict.valid(i):
+ return dict.entries[i].value
else:
ll_dict_setitem(dict, key, default)
return default
@@ -669,12 +706,12 @@
while i < dictsize:
d_entry = d.entries[i]
entry = dict.entries[i]
- ENTRY = lltype.typeOf(entry).TO
+ DICT = lltype.typeOf(dict).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
+ if DICT.entry_has_f_valid: d_entry.f_valid = entry.f_valid
+ if DICT.entry_has_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
+ if DICT.entry_has_f_hash: d_entry.f_hash = entry.f_hash
i += 1
return d
@@ -692,7 +729,7 @@
i = 0
while i < d2len:
entry = entries[i]
- if entry.valid():
+ if dic2.valid(i):
ll_dict_setitem(dic1, entry.key, entry.value)
i += 1
@@ -716,7 +753,7 @@
p = 0
while i < dlen:
entry = entries[i]
- if entry.valid():
+ if dic.valid(i):
ELEM = lltype.typeOf(items).TO.OF
if ELEM is not lltype.Void:
if func is dum_items:
@@ -733,5 +770,5 @@
return res
def ll_contains(d, key):
- entry = d.entries[ll_dict_lookup(d, key, d.keyhash(key))]
- return entry.valid()
+ i = ll_dict_lookup(d, key, d.keyhash(key))
+ return d.valid(i)
Modified: pypy/branch/rdict-index-based/pypy/rpython/test/test_rdict.py
==============================================================================
--- pypy/branch/rdict-index-based/pypy/rpython/test/test_rdict.py (original)
+++ pypy/branch/rdict-index-based/pypy/rpython/test/test_rdict.py Mon Sep 11 14:48:19 2006
@@ -548,7 +548,7 @@
res = self.interpret(func2, [ord(x), ord(y)])
for i in range(len(res.entries)):
- assert not (res.entries[i].everused() and not res.entries[i].valid())
+ assert not (res.everused(i) and not res.valid(i))
def func3(c0, c1, c2, c3, c4, c5, c6, c7):
d = {}
@@ -568,7 +568,7 @@
for i in range(rdict.DICT_INITSIZE)])
count_frees = 0
for i in range(len(res.entries)):
- if not res.entries[i].everused():
+ if not res.everused(i):
count_frees += 1
assert count_frees >= 3
@@ -659,8 +659,8 @@
res = self.interpret(f, [])
assert res.item0 == True
DICT = lltype.typeOf(res.item1).TO
- assert not hasattr(DICT.entries.TO.OF, 'f_everused')# non-None string keys
- assert not hasattr(DICT.entries.TO.OF, 'f_valid') # strings have a dummy
+ assert not DICT.entry_has_f_everused# non-None string keys
+ assert not DICT.entry_has_f_valid # strings have a dummy
def test_opt_nullvaluemarker(self):
def f(n):
@@ -670,8 +670,8 @@
res = self.interpret(f, [-5])
assert res.item0 == 4
DICT = lltype.typeOf(res.item1).TO
- assert not hasattr(DICT.entries.TO.OF, 'f_everused')# non-None str values
- assert not hasattr(DICT.entries.TO.OF, 'f_valid') # strs have a dummy
+ assert not DICT.entry_has_f_everused# non-None string keys
+ assert not DICT.entry_has_f_valid # strings have a dummy
def test_opt_nonullmarker(self):
class A:
@@ -687,8 +687,8 @@
res = self.interpret(f, [-5])
assert res.item0 == -5441
DICT = lltype.typeOf(res.item1).TO
- assert hasattr(DICT.entries.TO.OF, 'f_everused') # can-be-None A instances
- assert not hasattr(DICT.entries.TO.OF, 'f_valid')# with a dummy A instance
+ assert DICT.entry_has_f_everused # can-be-None A instances
+ assert not DICT.entry_has_f_valid# with a dummy A instance
res = self.interpret(f, [6])
assert res.item0 == -5441
@@ -703,8 +703,8 @@
assert res.item0 == 1
assert res.item1 == 24
DICT = lltype.typeOf(res.item2).TO
- assert hasattr(DICT.entries.TO.OF, 'f_everused') # all ints can be zero
- assert not hasattr(DICT.entries.TO.OF, 'f_valid')# nonneg int: dummy -1
+ assert DICT.entry_has_f_everused # all ints can be zero
+ assert not DICT.entry_has_f_valid# nonneg int: dummy -1
def test_opt_no_dummy(self):
def f(n):
@@ -716,8 +716,8 @@
assert res.item0 == 1
assert res.item1 == -24
DICT = lltype.typeOf(res.item2).TO
- assert hasattr(DICT.entries.TO.OF, 'f_everused') # all ints can be zero
- assert hasattr(DICT.entries.TO.OF, 'f_valid') # no dummy available
+ assert DICT.entry_has_f_everused # all ints can be zero
+ assert DICT.entry_has_f_valid # no dummy available
def test_opt_multiple_identical_dicts(self):
def f(n):
@@ -748,7 +748,3 @@
return dic[i]
res = self.interpret(func, [5])
assert res.ll_get(5) is res
-
-
-
-
More information about the Pypy-commit
mailing list