# HG changeset patch
# User Jeroen Demeyer <jdemeyer@cage.ugent.be>
# 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

b


76  76  # introduced in trac ticket #715 
77  77  
78  78  from weakref import KeyedRef 
79   from sage.structure.coerce_dict import TripleDict 
 79  from sage.structure.coerce_dict import signed_id, TripleDict 
80  80  _cache = TripleDict(53) 
81  81  
82  82  def Hom(X, Y, category=None): 
… 
… 

263  263  H = category.hom_category().parent_class(X, Y, category = category) 
264  264  
265  265  ##_cache[key] = weakref.ref(H) 
266   _cache[key] = KeyedRef(H, _cache.eraser, (id(X),id(Y),id(category))) 
 266  _cache[key] = KeyedRef(H, _cache.eraser, (signed_id(X),signed_id(Y),signed_id(category))) 
267  267  return H 
268  268  
269  269  def hom(X, Y, f): 
diff git a/sage/structure/coerce_dict.pyx b/sage/structure/coerce_dict.pyx
a

b


44  44  PyObject* PyWeakref_GetObject(object ref) 
45  45  PyObject* Py_None 
46  46  
 47  cpdef inline Py_ssize_t signed_id(x): 
 48  """ 
 49  A function like Python's :func:`id` returning *signed* integers, 
 50  which are guaranteed to fit in a ``Py_ssize_t``. 
 51  
 52  Theoretically, there is no guarantee that two different Python 
 53  objects have different ``signed_id()`` values. However, under the 
 54  mild assumption that a C pointer fits in a ``Py_ssize_t``, this 
 55  is guaranteed. 
 56  
 57  TESTS:: 
 58  
 59  sage: a = 1.23e45 # some object 
 60  sage: from sage.structure.coerce_dict import signed_id 
 61  sage: s = signed_id(a) 
 62  sage: id(a) == s or id(a) == s + 2**32 or id(a) == s + 2**64 
 63  True 
 64  sage: signed_id(a) <= sys.maxsize 
 65  True 
 66  """ 
 67  return <Py_ssize_t><void *>(x) 
 68  
47  69  import gc 
48  70  
49  71  ############################################ 
50  72  # A note about how to store "id" keys in python structures: 
51  73  # 
52   # In python a "pointer length integer" (size_t) normally, is encoded 
53   # as a *signed* integer, of type Py_ssize_t. This has an advantage in that 
54   # if the value gets encoded as a *python integer* it can do so in a signpreserving 
55   # way and still make use of all the bits that python offers to store (small) integers. 
 74  # We use the type Py_ssize_t to store "id"s generated by the signed_id 
 75  # function defined above. Assuming that Py_ssize_t is the same as a C 
 76  # long (which is true on most Unixlike systems), this also has the 
 77  # advantage that these Py_ssize_t values are stored as a Python "int" 
 78  # (as opposed to "long"), which allow for fast conversion to/from C 
 79  # types. 
56  80  # 
57  81  # There is one place where we have to be careful about signs: 
58  82  # Our hash values most naturally live in Py_ssize_t. We convert those into 
… 
… 

60  84  # However, the modulo operator in C preserves the sign of the number we take the 
61  85  # modulus of, which is not what we want. 
62  86  # The solution is to always do 
63   # (<size_t) h)% modulus 
 87  # (<size_t> h) % modulus 
64  88  # to ensure we're doing an unsigned modulus. 
65  89  
66  90  ############################################ 
… 
… 

528  552  sage: 15 in L 
529  553  False 
530  554  """ 
531   cdef Py_ssize_t h = <Py_ssize_t><void *>k 
 555  cdef Py_ssize_t h = signed_id(k) 
532  556  cdef Py_ssize_t i 
533  557  cdef list all_buckets = self.buckets 
534  558  cdef list bucket = <object>PyList_GET_ITEM(all_buckets, (<size_t>h)% PyList_GET_SIZE(all_buckets)) 
… 
… 

571  595  return self.get(k) 
572  596  
573  597  cdef get(self, object k): 
574   cdef Py_ssize_t h =<Py_ssize_t><void *>k 
 598  cdef Py_ssize_t h = signed_id(k) 
575  599  cdef Py_ssize_t i 
576  600  cdef list all_buckets = self.buckets 
577  601  cdef list bucket = <object>PyList_GET_ITEM(all_buckets, (<size_t>h) % PyList_GET_SIZE(all_buckets)) 
… 
… 

608  632  cdef set(self,object k, value): 
609  633  if self.threshold and self._size > len(self.buckets) * self.threshold: 
610  634  self.resize() 
611   cdef Py_ssize_t h = <Py_ssize_t><void *>k 
 635  cdef Py_ssize_t h = signed_id(k) 
612  636  cdef Py_ssize_t i 
613  637  cdef list bucket = <object>PyList_GET_ITEM(self.buckets,(<size_t> h) % PyList_GET_SIZE(self.buckets)) 
614  638  cdef object r 
… 
… 

679  703  sage: a in L 
680  704  False 
681  705  """ 
682   cdef Py_ssize_t h = <Py_ssize_t><void *>k 
 706  cdef Py_ssize_t h = signed_id(k) 
683  707  cdef object r 
684  708  cdef Py_ssize_t i 
685  709  cdef object tmp 
… 
… 

1101  1125  return self.get(k1, k2, k3) 
1102  1126  
1103  1127  cdef get(self, object k1, object k2, object k3): 
1104   cdef Py_ssize_t h1 = <Py_ssize_t><void *>k1 
1105   cdef Py_ssize_t h2 = <Py_ssize_t><void *>k2 
1106   cdef Py_ssize_t h3 = <Py_ssize_t><void *>k3 
 1128  cdef Py_ssize_t h1 = signed_id(k1) 
 1129  cdef Py_ssize_t h2 = signed_id(k2) 
 1130  cdef Py_ssize_t h3 = signed_id(k3) 
1107  1131  cdef Py_ssize_t h = (h1 + 13*h2 ^ 503*h3) 
1108  1132  
1109  1133  cdef object r1,r2,r3 
… 
… 

1149  1173  cdef set(self, object k1, object k2, object k3, value): 
1150  1174  if self.threshold and self._size > len(self.buckets) * self.threshold: 
1151  1175  self.resize() 
1152   cdef Py_ssize_t h1 = <Py_ssize_t><void *>k1 
1153   cdef Py_ssize_t h2 = <Py_ssize_t><void *>k2 
1154   cdef Py_ssize_t h3 = <Py_ssize_t><void *>k3 
 1176  cdef Py_ssize_t h1 = signed_id(k1) 
 1177  cdef Py_ssize_t h2 = signed_id(k2) 
 1178  cdef Py_ssize_t h3 = signed_id(k3) 
1155  1179  cdef Py_ssize_t h = (h1 + 13*h2 ^ 503*h3) 
1156  1180  
1157  1181  cdef object r1,r2,r3 
… 
… 

1234  1258  k1, k2, k3 = k 
1235  1259  except (TypeError,ValueError): 
1236  1260  raise KeyError, k 
1237   cdef Py_ssize_t h1 = <Py_ssize_t><void *>k1 
1238   cdef Py_ssize_t h2 = <Py_ssize_t><void *>k2 
1239   cdef Py_ssize_t h3 = <Py_ssize_t><void *>k3 
 1261  cdef Py_ssize_t h1 = signed_id(k1) 
 1262  cdef Py_ssize_t h2 = signed_id(k2) 
 1263  cdef Py_ssize_t h3 = signed_id(k3) 
1240  1264  cdef Py_ssize_t h = (h1 + 13*h2 ^ 503*h3) 
1241  1265  
1242  1266  cdef Py_ssize_t i 