Author: Lukas Diekmann <[email protected]>
Branch: set-strategies
Changeset: r49136:46455b9b0a9d
Date: 2011-04-30 11:35 +0200
http://bitbucket.org/pypy/pypy/changeset/46455b9b0a9d/
Log: First basic implementation of strategies for SetObjects
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
@@ -8,6 +8,19 @@
from pypy.interpreter.function import Defaults
from pypy.objspace.std.settype import set_typedef as settypedef
from pypy.objspace.std.frozensettype import frozenset_typedef as
frozensettypedef
+from pypy.rlib import rerased
+from pypy.rlib.objectmodel import instantiate
+
+def get_strategy_from_setdata(space, setdata):
+ from pypy.objspace.std.intobject import W_IntObject
+
+ keys_w = setdata.keys()
+ for item_w in setdata.keys():
+ if type(item_w) is not W_IntObject:
+ break;
+ if item_w is keys_w[-1]:
+ return space.fromcache(IntegerSetStrategy)
+ return space.fromcache(ObjectSetStrategy)
class W_BaseSetObject(W_Object):
typedef = None
@@ -21,18 +34,19 @@
return True
return False
-
def __init__(w_self, space, setdata):
"""Initialize the set by taking ownership of 'setdata'."""
assert setdata is not None
- w_self.setdata = setdata
+ w_self.strategy = get_strategy_from_setdata(space, setdata)
+ w_self.strategy.init_from_setdata(w_self, setdata)
def __repr__(w_self):
"""representation for debugging purposes"""
- reprlist = [repr(w_item) for w_item in w_self.setdata.keys()]
+ reprlist = [repr(w_item) for w_item in w_self.getkeys()]
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)
@@ -51,6 +65,38 @@
def setweakref(self, space, weakreflifeline):
self._lifeline_ = weakreflifeline
+ # _____________ strategy methods ________________
+
+ def clear(self):
+ self.strategy.clear(self)
+
+ def copy(self):
+ return self.strategy.copy(self)
+
+ def length(self):
+ return self.strategy.length(self)
+
+ def add(self, w_key):
+ self.strategy.add(self, w_key)
+
+ def getkeys(self):
+ return self.strategy.getkeys(self)
+
+ 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 update(self, w_other):
+ self.strategy.update(self, w_other)
+
+ def has_key(self, w_key):
+ return self.strategy.has_key(self, w_key)
+
+ def equals(self, w_other):
+ return self.strategy.equals(self, w_other)
+
class W_SetObject(W_BaseSetObject):
from pypy.objspace.std.settype import set_typedef as typedef
@@ -62,6 +108,151 @@
registerimplementation(W_SetObject)
registerimplementation(W_FrozensetObject)
+class SetStrategy(object):
+ 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
+
+ def length(self, w_set):
+ raise NotImplementedError
+
+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():
+ 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)
+ if w_iterable is not None:
+ for w_item in self.space.listview(w_iterable):
+ data[self.unwrap(w_item)] = None
+ return data
+
+ def length(self, w_set):
+ return len(self.cast_from_void_star(w_set.sstorage))
+
+ def clear(self, w_set):
+ 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 make it faster by using from_storage_and_strategy
+ clone = instantiate(type(w_set))
+ print clone
+ clone.strategy = w_set.strategy
+ return clone
+
+ def add(self, w_set, w_key):
+ print "hehe"
+ print w_set
+ print w_key
+ d = self.cast_from_void_star(w_set.sstorage)
+ d[self.unwrap(w_key)] = None
+
+ def getkeys(self, w_set):
+ keys = self.cast_from_void_star(w_set.sstorage).keys()
+ keys_w = [self.wrap(key) for key in keys]
+ 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
+
+ def equals(self, w_set, w_other):
+ if w_set.length() != w_other.length():
+ return False
+ items = self.cast_from_void_star(w_set.sstorage).keys()
+ for key in items:
+ if not w_other.has_key(self.wrap(key)):
+ return False
+ return True
+
+ def intersect(self, w_set, w_other):
+ if w_set.length() > w_other.length():
+ return w_other.intersect(w_set)
+
+ result = w_set._newobj(self.space, newset(self.space))
+ items = self.cast_from_void_star(w_set.sstorage).keys()
+ #XXX do it without wrapping when strategies are equal
+ for key in items:
+ w_key = self.wrap(key)
+ if w_other.has_key(w_key):
+ result.add(w_key)
+ return result
+
+ def intersect_multiple(self, w_set, others_w):
+ result = w_set
+ for w_other in others_w:
+ if isinstance(w_other, W_BaseSetObject):
+ # optimization only
+ result = w_set.intersect(w_other)
+ else:
+ result2 = w_set._newobj(self.space, newset(self.space))
+ for w_key in self.space.listview(w_other):
+ if result.has_key(w_key):
+ result2.add(w_key)
+ result = result2
+ return result
+
+ 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):
+ other_w = w_other.getkeys()
+ #XXX better solution!?
+ for w_key in other_w:
+ d[w_key] = None
+ return
+
+ elif w_set.strategy is w_other.strategy:
+ other = self.cast_to_void_star(w_other.sstorage)
+ d.update(other)
+ return
+
+ w_set.switch_to_object_strategy()
+ w_set.update(w_other)
+
+class IntegerSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy):
+ cast_to_void_star, cast_from_void_star =
rerased.new_erasing_pair("integer")
+ cast_to_void_star = staticmethod(cast_to_void_star)
+ cast_from_void_star = staticmethod(cast_from_void_star)
+
+ def unwrap(self, w_item):
+ return self.space.unwrap(w_item)
+
+ def wrap(self, item):
+ return self.space.wrap(item)
+
+class ObjectSetStrategy(AbstractUnwrappedSetStrategy, SetStrategy):
+ cast_to_void_star, cast_from_void_star = rerased.new_erasing_pair("object")
+ cast_to_void_star = staticmethod(cast_to_void_star)
+ cast_from_void_star = staticmethod(cast_from_void_star)
+
+ def unwrap(self, w_item):
+ return w_item
+
+ def wrap(self, item):
+ return item
+
class W_SetIterObject(W_Object):
from pypy.objspace.std.settype import setiter_typedef as typedef
@@ -121,9 +312,12 @@
return data
def _initialize_set(space, w_obj, w_iterable=None):
- w_obj.setdata.clear()
+ w_obj.clear()
if w_iterable is not None:
- w_obj.setdata = make_setdata_from_w_iterable(space, w_iterable)
+ 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)
def _convert_set_to_frozenset(space, w_obj):
if space.is_true(space.isinstance(w_obj, space.w_set)):
@@ -134,14 +328,6 @@
# helper functions for set operation on dicts
-def _is_eq(ld, rd):
- if len(ld) != len(rd):
- return False
- for w_key in ld:
- if w_key not in rd:
- return False
- return True
-
def _difference_dict(space, ld, rd):
result = newset(space)
for w_key in ld:
@@ -159,15 +345,6 @@
except KeyError:
pass
-def _intersection_dict(space, ld, rd):
- result = newset(space)
- if len(ld) > len(rd):
- ld, rd = rd, ld # loop over the smaller dict
- for w_key in ld:
- if w_key in rd:
- result[w_key] = None
- return result
-
def _isdisjoint_dict(ld, rd):
if len(ld) > len(rd):
ld, rd = rd, ld # loop over the smaller dict
@@ -220,7 +397,7 @@
This has no effect if the element is already present.
"""
- w_left.setdata[w_other] = None
+ w_left.add(w_other)
def set_copy__Set(space, w_set):
return w_set._newobj(space, w_set.setdata.copy())
@@ -280,13 +457,14 @@
def eq__Set_Set(space, w_left, w_other):
# optimization only (the general case is eq__Set_settypedef)
- return space.wrap(_is_eq(w_left.setdata, w_other.setdata))
+ return space.wrap(w_left.equals(w_other))
eq__Set_Frozenset = eq__Set_Set
eq__Frozenset_Frozenset = eq__Set_Set
eq__Frozenset_Set = eq__Set_Set
def eq__Set_settypedef(space, w_left, w_other):
+ #XXX what is faster: wrapping w_left or creating set from w_other
rd = make_setdata_from_w_iterable(space, w_other)
return space.wrap(_is_eq(w_left.setdata, rd))
@@ -471,8 +649,12 @@
return w_key
def and__Set_Set(space, w_left, w_other):
+ new_set = w_left.intersect(w_other)
+ return new_set
ld, rd = w_left.setdata, w_other.setdata
new_ld = _intersection_dict(space, ld, rd)
+ #XXX when both have same strategy, ini new set from storage
+ # therefore this must be moved to strategies
return w_left._newobj(space, new_ld)
and__Set_Frozenset = and__Set_Set
@@ -480,6 +662,8 @@
and__Frozenset_Frozenset = and__Set_Set
def _intersection_multiple(space, w_left, others_w):
+ return w_left.intersect_multiple(others_w)
+
result = w_left.setdata
for w_other in others_w:
if isinstance(w_other, W_BaseSetObject):
@@ -495,10 +679,9 @@
def set_intersection__Set(space, w_left, others_w):
if len(others_w) == 0:
- result = w_left.setdata.copy()
+ return w_left.setdata.copy()
else:
- result = _intersection_multiple(space, w_left, others_w)
- return w_left._newobj(space, result)
+ return _intersection_multiple(space, w_left, others_w)
frozenset_intersection__Frozenset = set_intersection__Set
@@ -579,24 +762,26 @@
inplace_xor__Set_Frozenset = inplace_xor__Set_Set
def or__Set_Set(space, w_left, w_other):
- ld, rd = w_left.setdata, w_other.setdata
- result = ld.copy()
- result.update(rd)
- return w_left._newobj(space, result)
+ w_copy = w_left.copy()
+ w_copy.update(w_other)
+ return w_copy
or__Set_Frozenset = or__Set_Set
or__Frozenset_Set = or__Set_Set
or__Frozenset_Frozenset = or__Set_Set
def set_union__Set(space, w_left, others_w):
- result = w_left.setdata.copy()
+ 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.setdata) # optimization only
+ result.update(w_other) # optimization only
else:
for w_key in space.listview(w_other):
- result[w_key] = None
- return w_left._newobj(space, result)
+ print result
+ result.add(w_key)
+ return result
frozenset_union__Frozenset = set_union__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
@@ -51,6 +51,13 @@
assert self.space.eq_w(s,u)
class AppTestAppSetTest:
+ def test_simple(self):
+ a = set([1,2,3])
+ b = set()
+ b.add(4)
+ a.union(b)
+ assert a == set([1,2,3,4])
+
def test_subtype(self):
class subset(set):pass
a = subset()
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit