Author: Maciej Fijalkowski <[email protected]>
Branch: 
Changeset: r65132:1d6d177a0c6e
Date: 2013-07-01 08:49 +0200
http://bitbucket.org/pypy/pypy/changeset/1d6d177a0c6e/

Log:    (andrewchambers) merge identity-set. This branch adds a set based on
        identity, just like identity dict.

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
@@ -26,7 +26,7 @@
     def __repr__(self):
         """representation for debugging purposes"""
         reprlist = [repr(w_item) for w_item in self.getkeys()]
-        return "<%s(%s)>" % (self.__class__.__name__, ', '.join(reprlist))
+        return "<%s(%s)(%s)>" % (self.__class__.__name__, self.strategy, ', 
'.join(reprlist))
 
     def from_storage_and_strategy(self, storage, strategy):
         obj = self._newobj(self.space, None)
@@ -780,6 +780,8 @@
             strategy = self.space.fromcache(StringSetStrategy)
         elif type(w_key) is W_UnicodeObject:
             strategy = self.space.fromcache(UnicodeSetStrategy)
+        elif self.space.type(w_key).compares_by_identity():
+            strategy = self.space.fromcache(IdentitySetStrategy)
         else:
             strategy = self.space.fromcache(ObjectSetStrategy)
         w_set.strategy = strategy
@@ -1336,6 +1338,41 @@
                 break
             d_obj[w_item] = None
 
+class IdentitySetStrategy(AbstractUnwrappedSetStrategy, SetStrategy):
+    erase, unerase = rerased.new_erasing_pair("identityset")
+    erase = staticmethod(erase)
+    unerase = staticmethod(unerase)
+    
+    def get_empty_storage(self):
+        return self.erase({})
+
+    def get_empty_dict(self):
+        return {}
+
+    def is_correct_type(self, w_key):
+        w_type = self.space.type(w_key)
+        return w_type.compares_by_identity()
+
+    def may_contain_equal_elements(self, strategy):
+        #empty first, probably more likely
+        if strategy is self.space.fromcache(EmptySetStrategy):
+            return False
+        if strategy is self.space.fromcache(IntegerSetStrategy):
+            return False
+        if strategy is self.space.fromcache(StringSetStrategy):
+            return False
+        if strategy is self.space.fromcache(UnicodeSetStrategy):
+            return False
+        return True
+
+    def unwrap(self, w_item):
+        return w_item
+
+    def wrap(self, item):
+        return item    
+    
+    def iter(self, w_set):
+        return IdentityIteratorImplementation(self.space, self, w_set)        
 
 class IteratorImplementation(object):
     def __init__(self, space, strategy, implementation):
@@ -1427,6 +1464,17 @@
         else:
             return None
 
+class IdentityIteratorImplementation(IteratorImplementation):
+    def __init__(self, space, strategy, w_set):
+        IteratorImplementation.__init__(self, space, strategy, w_set)
+        d = strategy.unerase(w_set.sstorage)
+        self.iterator = d.iterkeys()
+
+    def next_entry(self):
+        for key in self.iterator:
+            return self.space.wrap(key)
+        else:
+            return None
 
 class RDictIteratorImplementation(IteratorImplementation):
     def __init__(self, space, strategy, w_set):
@@ -1545,6 +1593,15 @@
         w_set.strategy = space.fromcache(UnicodeSetStrategy)
         w_set.sstorage = w_set.strategy.get_storage_from_list(iterable_w)
         return
+    
+    # check for compares by identity
+    for w_item in iterable_w:
+        if not space.type(w_item).compares_by_identity():
+            break
+    else:
+        w_set.strategy = space.fromcache(IdentitySetStrategy)
+        w_set.sstorage = w_set.strategy.get_storage_from_list(iterable_w)
+        return    
 
     w_set.strategy = space.fromcache(ObjectSetStrategy)
     w_set.sstorage = w_set.strategy.get_storage_from_list(iterable_w)
diff --git a/pypy/objspace/std/test/test_identityset.py 
b/pypy/objspace/std/test/test_identityset.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/test/test_identityset.py
@@ -0,0 +1,209 @@
+import py
+
+
+
+class AppTestIdentitySet(object):
+    
+    #needed for compares_by_identity
+    spaceconfig = {"objspace.std.withidentitydict": True}
+    
+    def setup_class(cls):
+        from pypy.objspace.std import identitydict
+        if cls.runappdirect:
+            py.test.skip("interp2app doesn't work on appdirect")
+    
+    def w_uses_strategy(self, s , obj):
+        import __pypy__
+        return s in __pypy__.internal_repr(obj)
+    
+    def test_use_identity_strategy(self):
+        
+        class Plain(object):
+            pass
+
+        class CustomEq(object):
+            def __eq__(self, other):
+                return True
+
+        class CustomCmp (object):
+            def __cmp__(self, other):
+                return 0
+
+        class CustomHash(object):
+            def __hash__(self):
+                return 0
+            
+        s = set()
+        
+        assert not self.uses_strategy('IdentitySetStrategy',s)
+        
+        s.add(Plain())
+        
+        assert self.uses_strategy('IdentitySetStrategy',s)
+        
+        for cls in [CustomEq,CustomCmp,CustomHash]:
+            s = set()
+            s.add(cls())
+            assert not self.uses_strategy('IdentitySetStrategy',s)
+        
+        
+    def test_use_identity_strategy_list(self):
+        
+        class X(object):
+            pass
+        
+        assert self.uses_strategy('IdentitySetStrategy',set([X(),X()]))
+        assert not self.uses_strategy('IdentitySetStrategy',set([X(),""]))
+        assert not self.uses_strategy('IdentitySetStrategy',set([X(),u""]))
+        assert not self.uses_strategy('IdentitySetStrategy',set([X(),1]))
+        
+    def test_identity_strategy_add(self):
+        
+        class X(object):
+            pass
+        
+        class NotIdent(object):
+            def __eq__(self,other):
+                pass
+        
+        s = set([X(),X()])
+        s.add('foo')
+        assert not self.uses_strategy('IdentitySetStrategy',s)
+        s = set([X(),X()])
+        s.add(NotIdent())
+        assert not self.uses_strategy('IdentitySetStrategy',s)
+    
+    def test_identity_strategy_sanity(self):
+        
+        class X(object):
+            pass
+        
+        class Y(object):
+            pass
+        
+        a,b,c,d,e,f = X(),Y(),X(),Y(),X(),Y()
+        
+        s = set([a,b]).union(set([c]))
+        assert self.uses_strategy('IdentitySetStrategy',s) 
+        assert set([a,b,c]) == s
+        s = set([a,b,c,d,e,f]) - set([d,e,f])
+        assert self.uses_strategy('IdentitySetStrategy',s)
+        assert set([a,b,c]) == s
+        
+        
+        s = set([a])
+        s.update([b,c])
+        
+        assert s == set([a,b,c])
+    
+    
+    def test_identity_strategy_iterators(self):
+        
+        class X(object):
+            pass
+        
+        s = set([X() for i in range(10)])
+        counter = 0
+        for item in s:
+            counter += 1
+            assert item in s
+        
+        assert counter == 10
+    
+    
+    def test_identity_strategy_other_cmp(self):
+        
+        #test tries to hit positive and negative in 
+        # may_contain_equal_elements
+        
+        class X(object):
+            pass
+            
+        s = set([X() for i in range(10)]) 
+        
+        assert s.intersection(set([1,2,3])) == set()
+        assert s.intersection(set(['a','b','c'])) == set()
+        assert s.intersection(set(['a','b','c'])) == set()
+        assert s.intersection(set([X(),X()])) == set()
+        
+        other = set(['a','b','c',s.__iter__().next()])
+        intersect = s.intersection(other)
+        assert len(intersect) == 1
+        assert intersect.__iter__().next() in s
+        assert intersect.__iter__().next() in other
+        
+    def test_class_monkey_patch(self):
+        
+        class X(object):
+            pass
+        
+        s = set()
+        
+        s.add(X())
+        assert self.uses_strategy('IdentitySetStrategy',s)
+        X.__eq__ = lambda self,other : None
+        s.add(X())
+        assert not self.uses_strategy('IdentitySetStrategy',s)
+        assert not self.uses_strategy('IdentitySetStrategy',set([X(),X()]))
+        assert not self.uses_strategy('IdentitySetStrategy',set([X(),""]))
+        assert not self.uses_strategy('IdentitySetStrategy',set([X(),u""]))
+        assert not self.uses_strategy('IdentitySetStrategy',set([X(),1]))
+        
+        # An interesting case, add an instance, mutate the class, 
+        # then add the same instance.
+        
+        class X(object):
+            pass
+        
+        s = set()
+        inst = X()
+        s.add(inst)
+        X.__eq__ = lambda x,y : x is y
+        s.add(inst)
+        
+        assert len(s) == 1
+        assert s.__iter__().next() is inst
+        assert not self.uses_strategy('IdentitySetStrategy',s)
+        
+        
+        #Add instance, mutate class, check membership of that instance.
+        
+        class X(object):
+            pass
+        
+        
+        inst = X()
+        s = set()
+        s.add(inst)
+        X.__eq__ = lambda x,y : x is y
+        assert inst in s
+        
+        # Test Wrong strategy
+        # If the strategy is changed by mutation, but the instance
+        # does not change, then this tests the methods that call
+        # may_contain_equal_elements still function.
+        # i.e. same instance in two sets, one with object strategy, one with
+        # identity strategy.
+        
+        class X(object):
+            pass
+        
+        
+        inst = X()
+        s1 = set()
+        s1.add(inst)
+        assert self.uses_strategy('IdentitySetStrategy',s1)
+        X.__eq__ = lambda x,y : x is y
+        s2 = set()
+        s2.add(inst)
+        assert not self.uses_strategy('IdentitySetStrategy',s2)
+        
+        assert s1.intersection(s2) == set([inst])
+        assert (s1 - s2) == set()
+        assert (s2 - s1) == set()
+        
+        s1.difference_update(s2)
+        assert s1 == set()
+        
+        
+        
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to