Author: Armin Rigo <ar...@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': '>>', _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit