Author: Maciej Fijalkowski <fij...@gmail.com> Branch: rdict-experiments-2 Changeset: r59816:290adf4d1f44 Date: 2013-01-06 22:14 +0200 http://bitbucket.org/pypy/pypy/changeset/290adf4d1f44/
Log: finish tests diff --git a/pypy/rpython/lltypesystem/llmemory.py b/pypy/rpython/lltypesystem/llmemory.py --- a/pypy/rpython/lltypesystem/llmemory.py +++ b/pypy/rpython/lltypesystem/llmemory.py @@ -90,6 +90,7 @@ try: endmarker = _end_markers[parent] except KeyError: + xxx endmarker = _endmarker_struct(A, parent=parent, parentindex=index) _end_markers[parent] = endmarker 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 @@ -3,6 +3,7 @@ from pypy.rpython.rdict import (AbstractDictRepr, AbstractDictIteratorRepr, rtype_newdict) from pypy.rpython.lltypesystem import lltype +from pypy.rpython.lltypesystem.lloperation import llop from pypy.rlib import objectmodel, jit, rgc from pypy.rlib.debug import ll_assert from pypy.rlib.rarithmetic import r_uint, intmask, LONG_BIT @@ -154,6 +155,8 @@ ll_hash_function=self.key_repr.get_ll_hash_function(), ll_eq_function=self.key_repr.get_ll_eq_function(), get_custom_eq_hash=self.custom_eq_hash) + if self.custom_eq_hash is not None: + self.r_rdict_eqfn, self.r_rdict_hashfn = self.custom_eq_hash() def convert_const(self, dictobj): from pypy.rpython.lltypesystem import llmemory @@ -366,7 +369,8 @@ def ll_dict_setitem(d, key, value): hash = d.keyhash(key) i = ll_dict_lookup(d, key, hash) - return _ll_dict_setitem_lookup_done(d, key, value, hash, i) + res = _ll_dict_setitem_lookup_done(d, key, value, hash, i) + return res def _look_inside_setitem(d, key, value, hash, i): return jit.isvirtual(d) and jit.isconstant(key) @@ -392,6 +396,7 @@ entry = d.entries[index] rc = d.resize_counter - 1 ll_assert(rc > 0, "ll_dict_resize failed?") + ll_assert(index < len(d.entries), "invalid insert") d.resize_counter = rc d.indexes[i] = index entry.value = value @@ -419,14 +424,13 @@ @jit.look_inside_iff(lambda d, i: jit.isvirtual(d) and jit.isconstant(i)) def _ll_dict_del(d, i): index = d.indexes[i] - d.indexes[i] = DELETED - d.num_items -= 1 ENTRIES = lltype.typeOf(d.entries).TO ENTRY = ENTRIES.OF - if index != d.num_items: - old_entry = d.entries[d.num_items] + if index != d.num_items - 1: + old_entry = d.entries[d.num_items - 1] key = old_entry.key to_insert_i = ll_dict_lookup(d, key, d.keyhash(key)) + ll_assert(not to_insert_i & HIGHEST_BIT, "invalid entry") d.indexes[to_insert_i] = index # copy the value new_entry = d.entries[index] @@ -435,6 +439,8 @@ if hasattr(ENTRY, 'f_hash'): new_entry.f_hash = old_entry.f_hash # clear the key and the value if they are GC pointers + d.indexes[i] = DELETED + d.num_items -= 1 entry = d.entries[d.num_items] if ENTRIES.must_clear_key: entry.key = lltype.nullptr(ENTRY.key.TO) @@ -471,8 +477,7 @@ new_item_size = new_size // 3 * 2 + 1 d.entries = lltype.typeOf(old_entries).TO.allocate(new_item_size) d.indexes = lltype.typeOf(d).TO.indexes.TO.allocate(new_size) - d.num_items = len(old_entries) - 1 - d.resize_counter = new_item_size + d.resize_counter = new_item_size - d.num_items i = 0 indexes = d.indexes while i < old_size: @@ -480,7 +485,8 @@ if index >= 0: indexes[ll_dict_lookup_clean(d, old_entries.hash(index))] = index i += 1 - rgc.ll_arraycopy(old_entries, d.entries, 0, 0, len(old_entries)) + rgc.ll_arraycopy(old_entries, d.entries, 0, 0, min(len(old_entries), + len(d.entries))) ll_dict_resize.oopspec = 'dict.resize(d)' # ------- a port of CPython's dictobject.c's lookdict implementation ------- @@ -535,7 +541,7 @@ elif index >= 0: checkingkey = entries[index].key if checkingkey == key: - return index + return i 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 @@ -710,24 +716,17 @@ return default def ll_copy(dict): - xxx DICT = lltype.typeOf(dict).TO dictsize = len(dict.entries) d = DICT.allocate() - d.entries = DICT.entries.TO.allocate(dictsize) + d.entries = lltype.malloc(DICT.entries.TO, dictsize) + d.indexes = DICT.indexes.TO.allocate(len(dict.indexes)) d.num_items = dict.num_items d.resize_counter = dict.resize_counter 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(d.entries).TO.OF - d_entry.key = entry.key - d_entry.value = entry.value - if hasattr(ENTRY, 'f_hash'): d_entry.f_hash = entry.f_hash - i += 1 + rgc.ll_arraycopy(dict.indexes, d.indexes, 0, 0, len(dict.indexes)) + rgc.ll_arraycopy(dict.entries, d.entries, 0, 0, len(dict.entries)) return d ll_copy.oopspec = 'dict.copy(dict)' @@ -743,17 +742,15 @@ ll_clear.oopspec = 'dict.clear(d)' def ll_update(dic1, dic2): - xxx entries = dic2.entries - d2len = len(entries) + d2len = dic2.num_items i = 0 while i < d2len: - if entries.valid(i): - entry = entries[i] - hash = entries.hash(i) - key = entry.key - j = ll_dict_lookup(dic1, key, hash) - _ll_dict_setitem_lookup_done(dic1, key, entry.value, hash, j) + entry = entries[i] + hash = entries.hash(i) + key = entry.key + j = ll_dict_lookup(dic1, key, hash) + _ll_dict_setitem_lookup_done(dic1, key, entry.value, hash, j) i += 1 ll_update.oopspec = 'dict.update(dic1, dic2)' @@ -772,27 +769,23 @@ def ll_kvi(LIST, dic): res = LIST.ll_newlist(dic.num_items) entries = dic.entries - dlen = len(entries) + dlen = dic.num_items items = res.ll_items() i = 0 - p = 0 while i < dlen: - if entries.valid(i): - ELEM = lltype.typeOf(items).TO.OF - if ELEM is not lltype.Void: - entry = entries[i] - if kind == '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 kind == 'keys': - items[p] = recast(ELEM, entry.key) - elif kind == 'values': - items[p] = recast(ELEM, entry.value) - p += 1 + ELEM = lltype.typeOf(items).TO.OF + if ELEM is not lltype.Void: + entry = entries[i] + if kind == 'items': + r = lltype.malloc(ELEM.TO) + r.item0 = recast(ELEM.TO.item0, entry.key) + r.item1 = recast(ELEM.TO.item1, entry.value) + items[i] = r + elif kind == 'keys': + items[i] = recast(ELEM, entry.key) + elif kind == 'values': + items[i] = recast(ELEM, entry.value) i += 1 - assert p == res.ll_length() return res ll_kvi.oopspec = 'dict.%s(dic)' % kind return ll_kvi @@ -805,40 +798,14 @@ i = ll_dict_lookup(d, key, d.keyhash(key)) return not i & HIGHEST_BIT -POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed)) -global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True) - -def _ll_getnextitem(dic): - entries = dic.entries - ENTRY = lltype.typeOf(entries).TO.OF - dmask = len(entries) - 1 - if hasattr(ENTRY, 'f_hash'): - if entries.valid(0): - return 0 - base = entries[0].f_hash - else: - base = global_popitem_index.nextindex - counter = 0 - while counter <= dmask: - i = (base + counter) & dmask - counter += 1 - if entries.valid(i): - break - else: +def ll_popitem(ELEM, dic): + if dic.num_items == 0: raise KeyError - if hasattr(ENTRY, 'f_hash'): - entries[0].f_hash = base + counter - else: - global_popitem_index.nextindex = base + counter - return i - -def ll_popitem(ELEM, dic): - i = _ll_getnextitem(dic) - entry = dic.entries[i] + entry = dic.entries[dic.num_items - 1] r = lltype.malloc(ELEM.TO) r.item0 = recast(ELEM.TO.item0, entry.key) r.item1 = recast(ELEM.TO.item1, entry.value) - _ll_dict_del(dic, i) + ll_dict_delitem(dic, entry.key) return r def ll_pop(dic, key): 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 @@ -91,6 +91,33 @@ assert hlstr(next) == "j" py.test.raises(StopIteration, ll_iterkeys, lltype.Signed, ll_iter) + def test_popitem(self): + DICT = self._get_str_dict() + ll_d = rdict.ll_newdict(DICT) + rdict.ll_dict_setitem(ll_d, llstr("k"), 1) + rdict.ll_dict_setitem(ll_d, llstr("j"), 2) + ll_elem = rdict.ll_popitem(lltype.Ptr( + lltype.GcStruct('x', ('item0', lltype.Ptr(rstr.STR)), + ('item1', lltype.Signed))), ll_d) + assert hlstr(ll_elem.item0) == "j" + assert ll_elem.item1 == 2 + + def test_direct_enter_and_del(self): + def eq(a, b): + return a == b + + DICT = rdict.get_ll_dict(lltype.Signed, lltype.Signed, + ll_fasthash_function=intmask, + ll_hash_function=intmask, + ll_eq_function=eq) + ll_d = rdict.ll_newdict(DICT) + numbers = [i * rdict.DICT_INITSIZE + 1 for i in range(8)] + for num in numbers: + rdict.ll_dict_setitem(ll_d, num, 1) + rdict.ll_dict_delitem(ll_d, num) + for k in ll_d.indexes: + assert k < 0 + class BaseTestRdict(BaseRtypingTest): def test_dict_creation(self): @@ -258,12 +285,12 @@ res = self.interpret(f, ()) assert res == 2 - def f(): + def f2(): d = {} d.setdefault('a', 2) x = d.setdefault('a', -3) return x - res = self.interpret(f, ()) + res = self.interpret(f2, ()) assert res == 2 def test_dict_copy(self): @@ -802,8 +829,7 @@ return d res = self.interpret(func2, [ord(x), ord(y)]) - for i in range(len(res.entries)): - assert not (res.entries.everused(i) and not res.entries.valid(i)) + assert len([i for i in res.indexes if i >= 0]) == 2 def func3(c0, c1, c2, c3, c4, c5, c6, c7): d = {} @@ -822,8 +848,8 @@ res = self.interpret(func3, [ord(char_by_hash[i][0]) for i in range(rdict.DICT_INITSIZE)]) count_frees = 0 - for i in range(len(res.entries)): - if not res.entries.everused(i): + for i in res.indexes: + if i == -1: count_frees += 1 assert count_frees >= 3 @@ -844,9 +870,9 @@ del d[chr(ord('A') - i)] return d res = self.interpret(func, [0]) - assert len(res.entries) > rdict.DICT_INITSIZE + assert len(res.indexes) > rdict.DICT_INITSIZE res = self.interpret(func, [1]) - assert len(res.entries) == rdict.DICT_INITSIZE + assert len(res.indexes) == rdict.DICT_INITSIZE def test_dict_valid_resize(self): # see if we find our keys after resize @@ -864,87 +890,6 @@ # ____________________________________________________________ - def test_opt_nullkeymarker(self): - def f(): - d = {"hello": None} - d["world"] = None - return "hello" in d, d - 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 - - def test_opt_nullvaluemarker(self): - def f(n): - d = {-5: "abcd"} - d[123] = "def" - return len(d[n]), d - 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 - - def test_opt_nonullmarker(self): - class A: - pass - def f(n): - if n > 5: - a = A() - else: - a = None - d = {a: -5441} - d[A()] = n+9872 - return d[a], d - 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 - - res = self.interpret(f, [6]) - assert res.item0 == -5441 - - def test_opt_nonnegint_dummy(self): - def f(n): - d = {n: 12} - d[-87] = 24 - del d[n] - return len(d.copy()), d[-87], d - res = self.interpret(f, [5]) - 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 - - def test_opt_no_dummy(self): - def f(n): - d = {n: 12} - d[-87] = -24 - del d[n] - return len(d.copy()), d[-87], d - res = self.interpret(f, [5]) - 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 - - def test_opt_boolean_has_no_dummy(self): - def f(n): - d = {n: True} - d[-87] = True - del d[n] - return len(d.copy()), d[-87], d - res = self.interpret(f, [5]) - assert res.item0 == 1 - assert res.item1 is True - 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 - def test_opt_multiple_identical_dicts(self): def f(n): s = "x" * n @@ -1159,7 +1104,7 @@ DictValue(None, annmodel.SomeString(value_can_be_none))) dictrepr.setup() print dictrepr.lowleveltype - for key, value in dictrepr.DICTENTRY._adtmeths.items(): + for key, value in dictrepr.DICT.entries.TO._adtmeths.items(): print ' %s = %s' % (key, value) l_dict = rdict.ll_newdict(dictrepr.DICT) referencetable = [None] * 400 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit