[pypy-commit] pypy default: Add id/is support to the empty frozenset, similar to the empty tuple

arigo pypy.commits at gmail.com
Mon Jun 13 13:41:06 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r85139:b80452987110
Date: 2016-06-13 19:40 +0200
http://bitbucket.org/pypy/pypy/changeset/b80452987110/

Log:	Add id/is support to the empty frozenset, similar to the empty tuple

diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -321,6 +321,8 @@
 
  - ``tuple`` (empty tuples only)
 
+ - ``frozenset`` (empty frozenset only)
+
 This change requires some changes to ``id`` as well. ``id`` fulfills the
 following condition: ``x is y <=> id(x) == id(y)``. Therefore ``id`` of the
 above types will return a value that is computed from the argument, and can
@@ -329,12 +331,13 @@
 Note that strings of length 2 or greater can be equal without being
 identical.  Similarly, ``x is (2,)`` is not necessarily true even if
 ``x`` contains a tuple and ``x == (2,)``.  The uniqueness rules apply
-only to the particular cases described above.  The ``str``, ``unicode``
-and ``tuple`` rules were added in PyPy 5.4; before that, a test like
-``if x is "?"`` or ``if x is ()`` could fail even if ``x`` was equal to
-``"?"`` or ``()``.  The new behavior added in PyPy 5.4 is closer to
-CPython's, which caches precisely the empty string, unicode and tuple,
-and (sometimes!) the single-character strings and unicodes.
+only to the particular cases described above.  The ``str``, ``unicode``,
+``tuple`` and ``frozenset`` rules were added in PyPy 5.4; before that, a
+test like ``if x is "?"`` or ``if x is ()`` could fail even if ``x`` was
+equal to ``"?"`` or ``()``.  The new behavior added in PyPy 5.4 is
+closer to CPython's, which caches precisely the empty
+string/unicode/tuple/frozenset, and (sometimes!) the single-character
+strings and unicodes.
 
 Note that for floats there "``is``" only one object per "bit pattern"
 of the float.  So ``float('nan') is float('nan')`` is true on PyPy,
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
@@ -6,6 +6,7 @@
 from pypy.objspace.std.bytesobject import W_BytesObject
 from pypy.objspace.std.intobject import W_IntObject
 from pypy.objspace.std.unicodeobject import W_UnicodeObject
+from pypy.objspace.std.util import IDTAG_SPECIAL, IDTAG_SHIFT
 
 from rpython.rlib.objectmodel import r_dict
 from rpython.rlib.objectmodel import iterkeys_with_hash, contains_with_hash
@@ -575,6 +576,23 @@
 class W_FrozensetObject(W_BaseSetObject):
     hash = 0
 
+    def is_w(self, space, w_other):
+        if not isinstance(w_other, W_FrozensetObject):
+            return False
+        if self is w_other:
+            return True
+        if self.user_overridden_class or w_other.user_overridden_class:
+            return False
+        # empty frozensets are unique-ified
+        return 0 == w_other.length() == self.length()
+
+    def immutable_unique_id(self, space):
+        if self.user_overridden_class or self.length() > 0:
+            return None
+        # empty frozenset: base value 259
+        uid = (259 << IDTAG_SHIFT) | IDTAG_SPECIAL
+        return space.wrap(uid)
+
     def _newobj(self, space, w_iterable):
         """Make a new frozenset by taking ownership of 'w_iterable'."""
         if type(self) is W_FrozensetObject:
diff --git a/pypy/objspace/std/test/test_obj.py b/pypy/objspace/std/test/test_obj.py
--- a/pypy/objspace/std/test/test_obj.py
+++ b/pypy/objspace/std/test/test_obj.py
@@ -204,6 +204,14 @@
             skip("cannot run this test as apptest")
         assert id(()) == (258 << 4) | 11     # always
 
+    def test_id_of_frozensets(self):
+        x = frozenset([4])
+        assert id(x) != id(frozenset([4]))          # no caching at all
+        if self.appdirect:
+            skip("cannot run this test as apptest")
+        assert id(frozenset()) == (259 << 4) | 11     # always
+        assert id(frozenset([])) == (259 << 4) | 11   # always
+
     def test_identity_vs_id_primitives(self):
         import sys
         l = range(-10, 10, 2)
@@ -218,12 +226,14 @@
             l.append(1 + i * 1j)
             l.append(1 - i * 1j)
             l.append((i,))
+            l.append(frozenset([i]))
         l.append(-0.0)
         l.append(None)
         l.append(True)
         l.append(False)
         l.append(())
         l.append(tuple([]))
+        l.append(frozenset())
 
         for i, a in enumerate(l):
             for b in l[i:]:
diff --git a/pypy/objspace/std/util.py b/pypy/objspace/std/util.py
--- a/pypy/objspace/std/util.py
+++ b/pypy/objspace/std/util.py
@@ -14,6 +14,7 @@
                       # 256: empty string
                       # 257: empty unicode
                       # 258: empty tuple
+                      # 259: empty frozenset
 
 CMP_OPS = dict(lt='<', le='<=', eq='==', ne='!=', gt='>', ge='>=')
 BINARY_BITWISE_OPS = {'and': '&', 'lshift': '<<', 'or': '|', 'rshift': '>>',


More information about the pypy-commit mailing list