Commits

Lukas Diekmann committed ddc6e9d

also copy storage of frozenset to avoid changing frozenset in methods like intersection, difference, etc

  • Participants
  • Parent commits 0dacc5b
  • Branches set-strategies

Comments (0)

Files changed (2)

File pypy/objspace/std/setobject.py

         """ Removes all elements from the set. """
         self.strategy.clear(self)
 
-    def copy(self):
-        """ Returns a clone of the set. """
-        return self.strategy.copy(self)
+    def copy_real(self):
+        """ Returns a clone of the set. Frozensets storages are also copied."""
+        return self.strategy.copy_real(self)
 
     def length(self):
         """ Returns the number of items inside the set. """
     def clear(self, w_set):
         raise NotImplementedError
 
-    def copy(self, w_set):
+    def copy_real(self, w_set):
         raise NotImplementedError
 
     def length(self, w_set):
     def clear(self, w_set):
         pass
 
-    def copy(self, w_set):
+    def copy_real(self, w_set):
         storage = self.erase(None)
         clone = w_set.from_storage_and_strategy(storage, self)
         return clone
         return False
 
     def difference(self, w_set, w_other):
-        return w_set.copy()
+        return w_set.copy_real()
 
     def difference_update(self, w_set, w_other):
         self.check_for_unhashable_objects(w_other)
 
     def intersect(self, w_set, w_other):
         self.check_for_unhashable_objects(w_other)
-        return w_set.copy()
+        return w_set.copy_real()
 
     def intersect_update(self, w_set, w_other):
         self.check_for_unhashable_objects(w_other)
-        return w_set.copy()
+        return w_set.copy_real()
 
     def intersect_multiple(self, w_set, others_w):
         self.intersect_multiple_update(w_set, others_w)
-        return w_set.copy()
+        return w_set.copy_real()
 
     def intersect_multiple_update(self, w_set, others_w):
         for w_other in others_w:
         return True
 
     def symmetric_difference(self, w_set, w_other):
-        return w_other.copy()
+        return w_other.copy_real()
 
     def symmetric_difference_update(self, w_set, w_other):
         w_set.strategy = w_other.strategy
     def clear(self, w_set):
         w_set.switch_to_empty_strategy()
 
-    def copy(self, w_set):
+    def copy_real(self, w_set):
         strategy = w_set.strategy
         if isinstance(w_set, W_FrozensetObject):
-            storage = w_set.sstorage
+            # only used internally since frozenset().copy()
+            # returns self in frozenset_copy__Frozenset
+            d = self.unerase(w_set.sstorage)
+            storage = self.erase(d.copy())
+            #storage = w_set.sstorage
         else:
             d = self.unerase(w_set.sstorage)
             storage = self.erase(d.copy())
 
     def intersect_multiple(self, w_set, others_w):
         #XXX find smarter implementations
-        result = w_set.copy()
+        result = w_set.copy_real()
         for w_other in others_w:
             if isinstance(w_other, W_BaseSetObject):
                 # optimization only
     w_left.add(w_other)
 
 def set_copy__Set(space, w_set):
-    return w_set.copy()
+    return w_set.copy_real()
 
 def frozenset_copy__Frozenset(space, w_left):
     if type(w_left) is W_FrozensetObject:
 
 def set_difference__Set(space, w_left, others_w):
     if len(others_w) == 0:
-        return w_left.copy()
-    result = w_left.copy()
+        return w_left.copy_real()
+    result = w_left.copy_real()
     set_difference_update__Set(space, result, others_w)
     return result
 
 
 def set_intersection__Set(space, w_left, others_w):
     if len(others_w) == 0:
-        return w_left.copy()
+        return w_left.copy_real()
     else:
         return _intersection_multiple(space, w_left, others_w)
 
 inplace_xor__Set_Frozenset = inplace_xor__Set_Set
 
 def or__Set_Set(space, w_left, w_other):
-    w_copy = w_left.copy()
+    w_copy = w_left.copy_real()
     w_copy.update(w_other)
     return w_copy
 
 or__Frozenset_Frozenset = or__Set_Set
 
 def set_union__Set(space, w_left, others_w):
-    result = w_left.copy()
+    result = w_left.copy_real()
     for w_other in others_w:
         if isinstance(w_other, W_BaseSetObject):
             result.update(w_other)     # optimization only

File pypy/objspace/std/test/test_setobject.py

         x.pop()
         assert x == set([2,3])
         assert y == set([1,2,3])
+
+    def test_never_change_frozenset(self):
+        a = frozenset([1,2])
+        b = a.copy()
+        assert a is b
+
+        a = frozenset([1,2])
+        b = a.union(set([3,4]))
+        assert b == set([1,2,3,4])
+        assert a == set([1,2])
+
+        a = frozenset()
+        b = a.union(set([3,4]))
+        assert b == set([3,4])
+        assert a == set()
+
+        a = frozenset([1,2])#multiple
+        b = a.union(set([3,4]),[5,6])
+        assert b == set([1,2,3,4,5,6])
+        assert a == set([1,2])
+
+        a = frozenset([1,2,3])
+        b = a.difference(set([3,4,5]))
+        assert b == set([1,2])
+        assert a == set([1,2,3])
+
+        a = frozenset([1,2,3])#multiple
+        b = a.difference(set([3]), [2])
+        assert b == set([1])
+        assert a == set([1,2,3])
+
+        a = frozenset([1,2,3])
+        b = a.symmetric_difference(set([3,4,5]))
+        assert b == set([1,2,4,5])
+        assert a == set([1,2,3])
+
+        a = frozenset([1,2,3])
+        b = a.intersection(set([3,4,5]))
+        assert b == set([3])
+        assert a == set([1,2,3])
+
+        a = frozenset([1,2,3])#multiple
+        b = a.intersection(set([2,3,4]), [2])
+        assert b == set([2])
+        assert a == set([1,2,3])
+
+        raises(AttributeError, "frozenset().update()")
+        raises(AttributeError, "frozenset().difference_update()")
+        raises(AttributeError, "frozenset().symmetric_difference_update()")
+        raises(AttributeError, "frozenset().intersection_update()")