Author: Lukas Diekmann <[email protected]>
Branch: set-strategies
Changeset: r49137:34fd0e9fa474
Date: 2011-05-01 16:19 +0200
http://bitbucket.org/pypy/pypy/changeset/34fd0e9fa474/
Log: All tests for setobject are working (but there is still untested
code)
diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py
--- a/pypy/objspace/std/setobject.py
+++ b/pypy/objspace/std/setobject.py
@@ -11,15 +11,25 @@
from pypy.rlib import rerased
from pypy.rlib.objectmodel import instantiate
-def get_strategy_from_setdata(space, setdata):
+def get_strategy_from_w_iterable(space, w_iterable=None):
from pypy.objspace.std.intobject import W_IntObject
+ #XXX what types for w_iterable are possible
- keys_w = setdata.keys()
- for item_w in setdata.keys():
+ if isinstance(w_iterable, W_BaseSetObject):
+ return w_iterable.strategy
+
+ if w_iterable is None:
+ #XXX becomes EmptySetStrategy later
+ return space.fromcache(ObjectSetStrategy)
+
+ if not isinstance(w_iterable, list):
+ w_iterable = space.listview(w_iterable)
+ for item_w in w_iterable:
if type(item_w) is not W_IntObject:
break;
- if item_w is keys_w[-1]:
+ if item_w is w_iterable[-1]:
return space.fromcache(IntegerSetStrategy)
+
return space.fromcache(ObjectSetStrategy)
class W_BaseSetObject(W_Object):
@@ -37,8 +47,9 @@
def __init__(w_self, space, setdata):
"""Initialize the set by taking ownership of 'setdata'."""
assert setdata is not None
- w_self.strategy = get_strategy_from_setdata(space, setdata)
- w_self.strategy.init_from_setdata(w_self, setdata)
+ w_self.space = space #XXX less memory without this indirection?
+ w_self.strategy = get_strategy_from_w_iterable(space, setdata.keys())
+ w_self.strategy.init_from_setdata_w(w_self, setdata)
def __repr__(w_self):
"""representation for debugging purposes"""
@@ -46,7 +57,6 @@
return "<%s(%s)>" % (w_self.__class__.__name__, ', '.join(reprlist))
def _newobj(w_self, space, rdict_w=None):
- print "_newobj"
"""Make a new set or frozenset by taking ownership of 'rdict_w'."""
#return space.call(space.type(w_self),W_SetIterObject(rdict_w))
objtype = type(w_self)
@@ -62,9 +72,15 @@
_lifeline_ = None
def getweakref(self):
return self._lifeline_
+
def setweakref(self, space, weakreflifeline):
self._lifeline_ = weakreflifeline
+ def switch_to_object_strategy(self, space):
+ d = self.strategy.getdict_w(self)
+ self.strategy = space.fromcache(ObjectSetStrategy)
+ self.sstorage = self.strategy.cast_to_void_star(d)
+
# _____________ strategy methods ________________
def clear(self):
@@ -79,15 +95,39 @@
def add(self, w_key):
self.strategy.add(self, w_key)
+ def discard(self, w_item):
+ return self.strategy.discard(self, w_item)
+
+ def delitem(self, w_item):
+ return self.strategy.delitem(self, w_item)
+
+ def getdict_w(self):
+ return self.strategy.getdict_w(self)
+
def getkeys(self):
return self.strategy.getkeys(self)
+ def difference(self, w_other):
+ return self.strategy.difference(self, w_other)
+
+ def difference_update(self, w_other):
+ return self.strategy.difference_update(self, w_other)
+
def intersect(self, w_other):
return self.strategy.intersect(self, w_other)
def intersect_multiple(self, others_w):
return self.strategy.intersect_multiple(self, others_w)
+ def intersect_multiple_update(self, others_w):
+ self.strategy.intersect_multiple_update(self, others_w)
+
+ def issubset(self, w_other):
+ return self.strategy.issubset(self, w_other)
+
+ def isdisjoint(self, w_other):
+ return self.strategy.isdisjoint(self, w_other)
+
def update(self, w_other):
self.strategy.update(self, w_other)
@@ -112,9 +152,6 @@
def __init__(self, space):
self.space = space
- def init_from_setdata(self, w_set, setdata):
- raise NotImplementedError
-
def init_from_w_iterable(self, w_set, setdata):
raise NotImplementedError
@@ -124,23 +161,24 @@
class AbstractUnwrappedSetStrategy(object):
__mixin__ = True
- def init_from_setdata(self, w_set, setdata):
- #XXX this copies again (see: make_setdata_from_w_iterable)
- #XXX cannot store int into r_dict
- d = newset(self.space)
- for item_w in setdata.keys():
+ def get_empty_storage(self):
+ raise NotImplementedError
+
+ def init_from_w_iterable(self, w_set, w_iterable):
+ setdata = self.make_setdata_from_w_iterable(w_iterable)
+ w_set.sstorage = self.cast_to_void_star(setdata)
+
+ def init_from_setdata_w(self, w_set, setdata_w):
+ d = self.get_empty_dict()
+ for item_w in setdata_w.keys():
d[self.unwrap(item_w)] = None
w_set.sstorage = self.cast_to_void_star(d)
- def ____init_from_w_iterable(self, w_set, w_iterable=None):
- keys = self.make_setdata_from_w_iterable(w_iterable)
- w_set.sstorage = self.cast_to_void_star(keys)
-
def make_setdata_from_w_iterable(self, w_iterable):
"""Return a new r_dict with the content of w_iterable."""
if isinstance(w_iterable, W_BaseSetObject):
return self.cast_from_void_star(w_set.sstorage).copy()
- data = newset(self.space)
+ data = self.get_empty_dict()
if w_iterable is not None:
for w_item in self.space.listview(w_iterable):
data[self.unwrap(w_item)] = None
@@ -153,21 +191,59 @@
self.cast_from_void_star(w_set.sstorage).clear()
def copy(self, w_set):
- print w_set
- d = self.cast_from_void_star(w_set.sstorage).copy()
- print d
+ #XXX do not copy FrozenDict
+ d = self.cast_from_void_star(w_set.sstorage)
#XXX make it faster by using from_storage_and_strategy
- clone = instantiate(type(w_set))
- print clone
+ clone = w_set._newobj(self.space, newset(self.space))
clone.strategy = w_set.strategy
+ clone.sstorage = self.cast_to_void_star(d.copy())
return clone
def add(self, w_set, w_key):
- print "hehe"
- print w_set
- print w_key
+ if self.is_correct_type(w_key):
+ d = self.cast_from_void_star(w_set.sstorage)
+ d[self.unwrap(w_key)] = None
+ else:
+ w_set.switch_to_object_strategy(self.space)
+ w_set.add(w_key)
+
+ def delitem(self, w_set, w_item):
d = self.cast_from_void_star(w_set.sstorage)
- d[self.unwrap(w_key)] = None
+ try:
+ del d[self.unwrap(w_item)]
+ except KeyError:
+ raise
+
+ def discard(self, w_set, w_item):
+ d = self.cast_from_void_star(w_set.sstorage)
+ try:
+ del d[self.unwrap(w_item)]
+ return True
+ except KeyError:
+ return False
+ except OperationError, e:
+ if not e.match(self.space, self.space.w_TypeError):
+ raise
+ w_f = _convert_set_to_frozenset(self.space, w_item)
+ if w_f is None:
+ raise
+ try:
+ del d[w_f]
+ return True
+ except KeyError:
+ return False
+ except OperationError, e:
+ #XXX is this ever tested?
+ if not e.match(space, space.w_TypeError):
+ raise
+ return False
+
+ def getdict_w(self, w_set):
+ result = newset(self.space)
+ keys = self.cast_from_void_star(w_set.sstorage).keys()
+ for key in keys:
+ result[self.wrap(key)] = None
+ return result
def getkeys(self, w_set):
keys = self.cast_from_void_star(w_set.sstorage).keys()
@@ -175,8 +251,8 @@
return keys_w
def has_key(self, w_set, w_key):
- items_w = self.cast_from_void_star(w_set.sstorage)
- return w_key in items_w
+ dict_w = self.cast_from_void_star(w_set.sstorage)
+ return self.unwrap(w_key) in dict_w
def equals(self, w_set, w_other):
if w_set.length() != w_other.length():
@@ -187,6 +263,27 @@
return False
return True
+ def difference(self, w_set, w_other):
+ result = w_set._newobj(self.space, newset(self.space))
+ if not isinstance(w_other, W_BaseSetObject):
+ #XXX this is bad
+ setdata = make_setdata_from_w_iterable(self.space, w_other)
+ w_other = w_set._newobj(self.space, setdata)
+ for w_key in w_set.getkeys():
+ if not w_other.has_key(w_key):
+ result.add(w_key)
+ return result
+
+ def difference_update(self, w_set, w_other):
+ if w_set is w_other:
+ w_set.clear() # for the case 'a.difference_update(a)'
+ else:
+ for w_key in w_other.getkeys():
+ try:
+ self.delitem(w_set, w_key)
+ except KeyError:
+ pass
+
def intersect(self, w_set, w_other):
if w_set.length() > w_other.length():
return w_other.intersect(w_set)
@@ -205,8 +302,10 @@
for w_other in others_w:
if isinstance(w_other, W_BaseSetObject):
# optimization only
- result = w_set.intersect(w_other)
+ #XXX this creates setobject again
+ result = result.intersect(w_other)
else:
+ #XXX directly give w_other as argument to result2
result2 = w_set._newobj(self.space, newset(self.space))
for w_key in self.space.listview(w_other):
if result.has_key(w_key):
@@ -214,6 +313,33 @@
result = result2
return result
+ def intersect_multiple_update(self, w_set, others_w):
+ #XXX faster withouth creating the setobject in intersect_multiple
+ result = self.intersect_multiple(w_set, others_w)
+ w_set.strategy = result.strategy
+ w_set.sstorage = result.sstorage
+
+ def issubset(self, w_set, w_other):
+ if w_set.length() > w_other.length():
+ return False
+
+ #XXX add ways without unwrapping if strategies are equal
+ for w_key in w_set.getkeys():
+ if not w_other.has_key(w_key):
+ return False
+ return True
+
+ def isdisjoint(self, w_set, w_other):
+ if w_set.length() > w_other.length():
+ return w_other.isdisjoint(w_set)
+
+ d = self.cast_from_void_star(w_set.sstorage)
+ for key in d:
+ #XXX no need to wrap, if strategies are equal
+ if w_other.has_key(self.wrap(key)):
+ return False
+ return True
+
def update(self, w_set, w_other):
d = self.cast_from_void_star(w_set.sstorage)
if w_set.strategy is self.space.fromcache(ObjectSetStrategy):
@@ -224,11 +350,10 @@
return
elif w_set.strategy is w_other.strategy:
- other = self.cast_to_void_star(w_other.sstorage)
+ other = self.cast_from_void_star(w_other.sstorage)
d.update(other)
return
-
- w_set.switch_to_object_strategy()
+ w_set.switch_to_object_strategy(self.space)
w_set.update(w_other)
class IntegerSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy):
@@ -236,6 +361,13 @@
cast_to_void_star = staticmethod(cast_to_void_star)
cast_from_void_star = staticmethod(cast_from_void_star)
+ def get_empty_dict(self):
+ return {}
+
+ def is_correct_type(self, w_key):
+ from pypy.objspace.std.intobject import W_IntObject
+ return type(w_key) is W_IntObject
+
def unwrap(self, w_item):
return self.space.unwrap(w_item)
@@ -247,6 +379,12 @@
cast_to_void_star = staticmethod(cast_to_void_star)
cast_from_void_star = staticmethod(cast_from_void_star)
+ def get_empty_dict(self):
+ return newset(self.space)
+
+ def is_correct_type(self, w_key):
+ return True
+
def unwrap(self, w_item):
return w_item
@@ -260,7 +398,7 @@
w_self.content = content = setdata
w_self.len = len(content)
w_self.pos = 0
- w_self.iterator = w_self.content.iterkeys()
+ w_self.iterator = iter(w_self.content)
def next_entry(w_self):
for w_key in w_self.iterator:
@@ -302,9 +440,11 @@
return r_dict(space.eq_w, space.hash_w)
def make_setdata_from_w_iterable(space, w_iterable=None):
+ #XXX remove this later
"""Return a new r_dict with the content of w_iterable."""
if isinstance(w_iterable, W_BaseSetObject):
- return w_iterable.setdata.copy()
+ #XXX is this bad or not?
+ return w_iterable.getdict_w()
data = newset(space)
if w_iterable is not None:
for w_item in space.listview(w_iterable):
@@ -314,13 +454,16 @@
def _initialize_set(space, w_obj, w_iterable=None):
w_obj.clear()
if w_iterable is not None:
- setdata = make_setdata_from_w_iterable(space, w_iterable)
- #XXX maybe this is not neccessary
- w_obj.strategy = get_strategy_from_setdata(space, setdata)
- w_obj.strategy.init_from_setdata(w_obj, setdata)
+ w_obj.strategy = get_strategy_from_w_iterable(space, w_iterable)
+ w_obj.strategy.init_from_w_iterable(w_obj, w_iterable)
def _convert_set_to_frozenset(space, w_obj):
+ #XXX can be optimized
if space.is_true(space.isinstance(w_obj, space.w_set)):
+ w_frozen = instantiate(W_FrozensetObject)
+ w_frozen.strategy = w_obj.strategy
+ w_frozen.sstorage = w_obj.sstorage
+ return w_frozen
return W_FrozensetObject(space,
make_setdata_from_w_iterable(space, w_obj))
else:
@@ -377,13 +520,12 @@
def set_update__Set(space, w_left, others_w):
"""Update a set with the union of itself and another."""
- ld = w_left.setdata
for w_other in others_w:
if isinstance(w_other, W_BaseSetObject):
- ld.update(w_other.setdata) # optimization only
+ w_left.update(w_other) # optimization only
else:
for w_key in space.listview(w_other):
- ld[w_key] = None
+ w_left.add(w_key)
def inplace_or__Set_Set(space, w_left, w_other):
ld, rd = w_left.setdata, w_other.setdata
@@ -400,7 +542,7 @@
w_left.add(w_other)
def set_copy__Set(space, w_set):
- return w_set._newobj(space, w_set.setdata.copy())
+ return w_set.copy()
def frozenset_copy__Frozenset(space, w_left):
if type(w_left) is W_FrozensetObject:
@@ -421,30 +563,31 @@
sub__Frozenset_Frozenset = sub__Set_Set
def set_difference__Set(space, w_left, others_w):
- result = w_left.setdata
if len(others_w) == 0:
- result = result.copy()
+ return w_left.copy()
+ result = w_left
for w_other in others_w:
- if isinstance(w_other, W_BaseSetObject):
- rd = w_other.setdata # optimization only
- else:
- rd = make_setdata_from_w_iterable(space, w_other)
- result = _difference_dict(space, result, rd)
- return w_left._newobj(space, result)
+ result = result.difference(w_other)
+ #if isinstance(w_other, W_BaseSetObject):
+ # rd = w_other.setdata # optimization only
+ #else:
+ # rd = make_setdata_from_w_iterable(space, w_other)
+ #result = _difference_dict(space, result, rd)
+ return result
frozenset_difference__Frozenset = set_difference__Set
def set_difference_update__Set(space, w_left, others_w):
- ld = w_left.setdata
for w_other in others_w:
if isinstance(w_other, W_BaseSetObject):
# optimization only
- _difference_dict_update(space, ld, w_other.setdata)
+ w_left.difference_update(w_other)
+ #_difference_dict_update(space, ld, w_other.setdata)
else:
for w_key in space.listview(w_other):
try:
- del ld[w_key]
+ w_left.delitem(w_key)
except KeyError:
pass
@@ -480,6 +623,7 @@
eq__Frozenset_ANY = eq__Set_ANY
def ne__Set_Set(space, w_left, w_other):
+ return space.wrap(not w_left.equals(w_other))
return space.wrap(not _is_eq(w_left.setdata, w_other.setdata))
ne__Set_Frozenset = ne__Set_Set
@@ -503,12 +647,12 @@
def contains__Set_ANY(space, w_left, w_other):
try:
- return space.newbool(w_other in w_left.setdata)
+ return space.newbool(w_left.has_key(w_other))
except OperationError, e:
if e.match(space, space.w_TypeError):
w_f = _convert_set_to_frozenset(space, w_other)
if w_f is not None:
- return space.newbool(w_f in w_left.setdata)
+ return space.newbool(w_left.has_key(w_f))
raise
contains__Frozenset_ANY = contains__Set_ANY
@@ -517,6 +661,8 @@
# optimization only (the general case works too)
if space.is_w(w_left, w_other):
return space.w_True
+ return space.wrap(w_left.issubset(w_other))
+
ld, rd = w_left.setdata, w_other.setdata
return space.wrap(_issubset_dict(ld, rd))
@@ -540,9 +686,11 @@
def set_issuperset__Set_Set(space, w_left, w_other):
# optimization only (the general case works too)
+ #XXX this is the same code as in set_issubset__Set_Set (sets reversed)
if space.is_w(w_left, w_other):
return space.w_True
+ return space.wrap(w_other.issubset(w_left))
ld, rd = w_left.setdata, w_other.setdata
return space.wrap(_issubset_dict(rd, ld))
@@ -567,7 +715,7 @@
# automatic registration of "lt(x, y)" as "not ge(y, x)" would not give the
# correct answer here!
def lt__Set_Set(space, w_left, w_other):
- if len(w_left.setdata) >= len(w_other.setdata):
+ if w_left.length() >= w_other.length():
return space.w_False
else:
return le__Set_Set(space, w_left, w_other)
@@ -577,7 +725,7 @@
lt__Frozenset_Frozenset = lt__Set_Set
def gt__Set_Set(space, w_left, w_other):
- if len(w_left.setdata) <= len(w_other.setdata):
+ if w_left.length() <= w_other.length():
return space.w_False
else:
return ge__Set_Set(space, w_left, w_other)
@@ -592,6 +740,9 @@
frozenset if the argument is a set.
Returns True if successfully removed.
"""
+ x = w_left.discard(w_item)
+ return x
+
try:
del w_left.setdata[w_item]
return True
@@ -626,8 +777,8 @@
if w_set.hash != 0:
return space.wrap(w_set.hash)
hash = 1927868237
- hash *= (len(w_set.setdata) + 1)
- for w_item in w_set.setdata:
+ hash *= (w_set.length() + 1)
+ for w_item in w_set.getkeys():
h = space.hash_w(w_item)
value = ((h ^ (h << 16) ^ 89869747) * multi)
hash = intmask(hash ^ value)
@@ -668,6 +819,8 @@
for w_other in others_w:
if isinstance(w_other, W_BaseSetObject):
# optimization only
+ #XXX test this
+ assert False
result = _intersection_dict(space, result, w_other.setdata)
else:
result2 = newset(space)
@@ -679,13 +832,15 @@
def set_intersection__Set(space, w_left, others_w):
if len(others_w) == 0:
- return w_left.setdata.copy()
+ return w_left.copy()
else:
return _intersection_multiple(space, w_left, others_w)
frozenset_intersection__Frozenset = set_intersection__Set
def set_intersection_update__Set(space, w_left, others_w):
+ w_left.intersect_multiple_update(others_w)
+ return
result = _intersection_multiple(space, w_left, others_w)
w_left.setdata = result
@@ -699,6 +854,7 @@
def set_isdisjoint__Set_Set(space, w_left, w_other):
# optimization only (the general case works too)
+ return space.newbool(w_left.isdisjoint(w_other))
ld, rd = w_left.setdata, w_other.setdata
disjoint = _isdisjoint_dict(ld, rd)
return space.newbool(disjoint)
@@ -708,9 +864,10 @@
set_isdisjoint__Frozenset_Set = set_isdisjoint__Set_Set
def set_isdisjoint__Set_ANY(space, w_left, w_other):
- ld = w_left.setdata
+ #XXX maybe checking if type fits strategy first (before comparing) speeds
this up a bit
+ # since this will be used in many other functions -> general function
for that
for w_key in space.listview(w_other):
- if w_key in ld:
+ if w_left.has_key(w_key):
return space.w_False
return space.w_True
@@ -771,27 +928,24 @@
or__Frozenset_Frozenset = or__Set_Set
def set_union__Set(space, w_left, others_w):
- print "hallo", w_left
result = w_left.copy()
- print result
for w_other in others_w:
if isinstance(w_other, W_BaseSetObject):
result.update(w_other) # optimization only
else:
for w_key in space.listview(w_other):
- print result
result.add(w_key)
return result
frozenset_union__Frozenset = set_union__Set
def len__Set(space, w_left):
- return space.newint(len(w_left.setdata))
+ return space.newint(w_left.length())
len__Frozenset = len__Set
def iter__Set(space, w_left):
- return W_SetIterObject(w_left.setdata)
+ return W_SetIterObject(w_left.getkeys())
iter__Frozenset = iter__Set
diff --git a/pypy/objspace/std/test/test_setobject.py
b/pypy/objspace/std/test/test_setobject.py
--- a/pypy/objspace/std/test/test_setobject.py
+++ b/pypy/objspace/std/test/test_setobject.py
@@ -55,13 +55,16 @@
a = set([1,2,3])
b = set()
b.add(4)
- a.union(b)
- assert a == set([1,2,3,4])
+ c = a.union(b)
+ assert c == set([1,2,3,4])
def test_subtype(self):
class subset(set):pass
a = subset()
+ print "a: ", type(a)
b = a | set('abc')
+ print b
+ print "b: ", type(b)
assert type(b) is subset
def test_union(self):
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit