Author: Armin Rigo <ar...@tunes.org> Branch: stmgc-c8-dictiter Changeset: r80557:cf95b2a3e1ca Date: 2015-11-05 22:59 +0100 http://bitbucket.org/pypy/pypy/changeset/cf95b2a3e1ca/
Log: stmset.__iter__ diff --git a/pypy/module/pypystm/stmset.py b/pypy/module/pypystm/stmset.py --- a/pypy/module/pypystm/stmset.py +++ b/pypy/module/pypystm/stmset.py @@ -2,6 +2,7 @@ The class pypystm.stmset, giving a part of the regular 'set' interface """ +from pypy.interpreter.error import OperationError from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.typedef import TypeDef from pypy.interpreter.gateway import interp2app @@ -150,8 +151,48 @@ return space.wrap(self.get_length()) def iter_w(self, space): - # not a real lazy iterator! - return space.iter(space.newlist(self.get_items_w())) + return W_STMSetIter(self.h) + + +class W_STMSetIter(W_Root): + _immutable_fields_ = ["hiter"] + next_from_same_hash = 0 + + def __init__(self, hobj): + self.hiter = hobj.iterentries() + + def descr_iter(self, space): + return self + + def descr_length_hint(self, space): + # xxx estimate: doesn't remove the items already yielded, + # and uses the faster len_estimate(); on the other hand, + # counts only one for every 64-bit hash value + return space.wrap(self.hiter.hashtable.len_estimate()) + + def descr_next(self, space): + if self.next_from_same_hash == 0: # common case + try: + entry = self.hiter.next() + except StopIteration: + raise OperationError(space.w_StopIteration, space.w_None) + index = 0 + array = lltype.cast_opaque_ptr(PARRAY, entry.object) + else: + index = self.next_from_same_hash + array = self.next_array + self.next_from_same_hash = 0 + self.next_array = lltype.nullptr(ARRAY) + # + if len(array) > index + 1: # uncommon case + self.next_from_same_hash = index + 1 + self.next_array = array + # + return cast_gcref_to_instance(W_Root, array[index]) + + def _cleanup_(self): + raise Exception("seeing a prebuilt %r object" % ( + self.__class__,)) def W_STMSet___new__(space, w_subtype): @@ -170,3 +211,10 @@ __len__ = interp2app(W_STMSet.len_w), __iter__ = interp2app(W_STMSet.iter_w), ) + +W_STMSetIter.typedef = TypeDef( + "stmset_iter", + __iter__ = interp2app(W_STMSetIter.descr_iter), + next = interp2app(W_STMSetIter.descr_next), + __length_hint__ = interp2app(W_STMSetIter.descr_length_hint), + ) diff --git a/pypy/module/pypystm/test/test_stmset.py b/pypy/module/pypystm/test/test_stmset.py --- a/pypy/module/pypystm/test/test_stmset.py +++ b/pypy/module/pypystm/test/test_stmset.py @@ -83,3 +83,19 @@ assert len(s) == 2 items = list(s) assert items == [42.5, key3] or items == [key3, 42.5] + + def test_iterator(self): + import pypystm + class A(object): + def __hash__(self): + return 42 + class B(object): + pass + d = pypystm.stmset() + a1 = A() + a2 = A() + b0 = B() + d.add(a1) + d.add(a2) + d.add(b0) + assert sorted(d) == sorted([a1, a2, b0]) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit