# HG changeset patch
# User Jeroen Demeyer
# Date 1363013396 -3600
# Node ID 8b20a357824aec78a8465200b416824f9c7aef00
# Parent 6400f8af57137e6d53f4d4462161c88cfbe6643c
Add a signed_id() function returning an "id" as Py_ssize_t
diff --git a/sage/categories/homset.py b/sage/categories/homset.py
--- a/sage/categories/homset.py
+++ b/sage/categories/homset.py
@@ -76,7 +76,7 @@
# introduced in trac ticket #715
from weakref import KeyedRef
-from sage.structure.coerce_dict import TripleDict
+from sage.structure.coerce_dict import signed_id, TripleDict
_cache = TripleDict(53)
def Hom(X, Y, category=None):
@@ -263,7 +263,7 @@
H = category.hom_category().parent_class(X, Y, category = category)
##_cache[key] = weakref.ref(H)
- _cache[key] = KeyedRef(H, _cache.eraser, (id(X),id(Y),id(category)))
+ _cache[key] = KeyedRef(H, _cache.eraser, (signed_id(X),signed_id(Y),signed_id(category)))
return H
def hom(X, Y, f):
diff --git a/sage/structure/coerce_dict.pyx b/sage/structure/coerce_dict.pyx
--- a/sage/structure/coerce_dict.pyx
+++ b/sage/structure/coerce_dict.pyx
@@ -44,15 +44,39 @@
PyObject* PyWeakref_GetObject(object ref)
PyObject* Py_None
+cpdef inline Py_ssize_t signed_id(x):
+ """
+ A function like Python's :func:`id` returning *signed* integers,
+ which are guaranteed to fit in a ``Py_ssize_t``.
+
+ Theoretically, there is no guarantee that two different Python
+ objects have different ``signed_id()`` values. However, under the
+ mild assumption that a C pointer fits in a ``Py_ssize_t``, this
+ is guaranteed.
+
+ TESTS::
+
+ sage: a = 1.23e45 # some object
+ sage: from sage.structure.coerce_dict import signed_id
+ sage: s = signed_id(a)
+ sage: id(a) == s or id(a) == s + 2**32 or id(a) == s + 2**64
+ True
+ sage: signed_id(a) <= sys.maxsize
+ True
+ """
+ return (x)
+
import gc
############################################
# A note about how to store "id" keys in python structures:
#
-# In python a "pointer length integer" (size_t) normally, is encoded
-# as a *signed* integer, of type Py_ssize_t. This has an advantage in that
-# if the value gets encoded as a *python integer* it can do so in a sign-preserving
-# way and still make use of all the bits that python offers to store (small) integers.
+# We use the type Py_ssize_t to store "id"s generated by the signed_id
+# function defined above. Assuming that Py_ssize_t is the same as a C
+# long (which is true on most Unix-like systems), this also has the
+# advantage that these Py_ssize_t values are stored as a Python "int"
+# (as opposed to "long"), which allow for fast conversion to/from C
+# types.
#
# There is one place where we have to be careful about signs:
# Our hash values most naturally live in Py_ssize_t. We convert those into
@@ -60,7 +84,7 @@
# However, the modulo operator in C preserves the sign of the number we take the
# modulus of, which is not what we want.
# The solution is to always do
-# ( h) % modulus
# to ensure we're doing an unsigned modulus.
############################################
@@ -528,7 +552,7 @@
sage: 15 in L
False
"""
- cdef Py_ssize_t h = k
+ cdef Py_ssize_t h = signed_id(k)
cdef Py_ssize_t i
cdef list all_buckets = self.buckets
cdef list bucket =