# HG changeset patch
# User JeanPierre Flori <jeanpierre.flor@ssi.gouv.fr>
# Date 1334152948 7200
# Node ID 3d6d0c5e1a8c69f177ec44771c5e01af356afcff
# Parent cbfa7f143f6d702264ca30e64b08bb4f728c53df
#715: the C % operator can return negative results.
diff git a/sage/structure/coerce_dict.pyx b/sage/structure/coerce_dict.pyx
a

b


93  93  sage: len(T) # indirect doctest 
94  94  0 
95  95  """ 
96   # r is a (weak) reference (typically to a parent), 
97   # and it knows the stored key of the unique triple r() had been part of. 
98   # 
 96  # r is a (weak) reference (typically to a parent), and it knows the 
 97  # stored key of the unique triple r() had been part of. 
99  98  # We remove that unique triple from self.D 
100   cdef Py_ssize_t k1,k2,k3 
 99  cdef size_t k1,k2,k3 
101  100  k1,k2,k3 = r.key 
102   cdef int h = (k1 + 13*k2 ^ 503*k3) % PyList_GET_SIZE(self.D.buckets) 
103   cdef list bucket = <object>PyList_GET_ITEM(self.D.buckets,h) 
 101  cdef size_t h = (k1 + 13*k2 ^ 503*k3) 
 102  cdef list bucket = <object>PyList_GET_ITEM(self.D.buckets, h % PyList_GET_SIZE(self.D.buckets)) 
104  103  cdef int i 
105  104  for i from 0 <= i < PyList_GET_SIZE(bucket) by 4: 
106   if <Py_ssize_t><object>PyList_GET_ITEM(bucket,i)==k1 and \ 
107   <Py_ssize_t><object>PyList_GET_ITEM(bucket,i+1)==k2 and \ 
108   <Py_ssize_t><object>PyList_GET_ITEM(bucket,i+2)==k3: 
 105  if <size_t><object>PyList_GET_ITEM(bucket, i)==k1 and \ 
 106  <size_t><object>PyList_GET_ITEM(bucket, i+1)==k2 and \ 
 107  <size_t><object>PyList_GET_ITEM(bucket, i+2)==k3: 
109  108  del bucket[i:i+4] 
110  109  self.D._size = 1 
111  110  break 
… 
… 

211  210  sage: len(LE) # indirect doctest 
212  211  1 
213  212  
 213  ..NOTE:: 
 214  
 215  The index `h` corresponding to the key [k1, k2, k3] is computed as a 
 216  value of unsigned type size_t as follows: 
 217  
 218  ..MATH:: 
 219  
 220  h = id(k1) + 13*id(k2) \oplus 503 id(k3) 
 221  
 222  Indeed, although the PyList_GetItem function and corresponding 
 223  PyList_GET_ITEM macro take a value of signed type Py_ssize_t as input 
 224  for the index, they do not accept negative inputs as the higher level 
 225  Python functions. Moreover, the above formula can overflow so that `h` 
 226  might be considered as negative. Even though this value is taken 
 227  modulo the size of the buckets' list before accessing the corresponding 
 228  item, the Cython "%" operator behaves for values of type size_t and 
 229  Py_ssize_t like the C "%" operator, rather than like the Python "%" 
 230  operator as it does for values of type int. That is, it returns a 
 231  result of the same sign as its input. Therefore, if `h` was defined as 
 232  a signed value, we might access the list at a negative index and raise 
 233  a segfault (and this has been observed on 32 bits systems, see 
 234  :trac:`715` for details). 
 235  
214  236  AUTHORS: 
215  237  
216  238   Robert Bradshaw, 200708 
… 
… 

353  375  return self.get(k1, k2, k3) 
354  376  
355  377  cdef get(self, object k1, object k2, object k3): 
356   cdef Py_ssize_t h = (<Py_ssize_t><void *>k1 + 13*<Py_ssize_t><void *>k2 ^ 503*<Py_ssize_t><void *>k3) 
357   #if h < 0: h = h # shouldn't "%" result in a positive number anyway? 
 378  cdef size_t h = (<size_t><void *>k1 + 13*<size_t><void *>k2 ^ 503*<size_t><void *>k3) 
358  379  cdef Py_ssize_t i 
359  380  cdef list all_buckets = self.buckets 
360  381  cdef list bucket = <object>PyList_GET_ITEM(all_buckets, h % PyList_GET_SIZE(all_buckets)) 
361  382  cdef object tmp 
362  383  for i from 0 <= i < PyList_GET_SIZE(bucket) by 4: 
363  384  tmp = <object>PyList_GET_ITEM(bucket, i) 
364   if <Py_ssize_t>tmp == <Py_ssize_t><void *>k1: 
 385  if <size_t>tmp == <size_t><void *>k1: 
365  386  tmp = <object>PyList_GET_ITEM(bucket, i+1) 
366   if <Py_ssize_t>tmp == <Py_ssize_t><void *>k2: 
 387  if <size_t>tmp == <size_t><void *>k2: 
367  388  tmp = <object>PyList_GET_ITEM(bucket, i+2) 
368   if <Py_ssize_t>tmp == <Py_ssize_t><void *>k3: 
 389  if <size_t>tmp == <size_t><void *>k3: 
369  390  return <object>PyList_GET_ITEM(bucket, i+3) 
370  391  raise KeyError, (k1, k2, k3) 
371  392  
… 
… 

390  411  cdef set(self, object k1, object k2, object k3, value): 
391  412  if self.threshold and self._size > len(self.buckets) * self.threshold: 
392  413  self.resize() 
393   cdef Py_ssize_t h1 = <Py_ssize_t><void *>k1 
394   cdef Py_ssize_t h2 = <Py_ssize_t><void *>k2 
395   cdef Py_ssize_t h3 = <Py_ssize_t><void *>k3 
396   
397   cdef Py_ssize_t h = (h1 + 13*h2 ^ 503*h3) 
398   #if h < 0: h = h # shouldn't "%" return a positive number anyway? 
 414  cdef size_t h1 = <size_t><void *>k1 
 415  cdef size_t h2 = <size_t><void *>k2 
 416  cdef size_t h3 = <size_t><void *>k3 
 417  cdef size_t h = (h1 + 13*h2 ^ 503*h3) 
399  418  cdef Py_ssize_t i 
400  419  cdef list bucket = <object>PyList_GET_ITEM(self.buckets, h % PyList_GET_SIZE(self.buckets)) 
401  420  cdef object tmp 
402  421  for i from 0 <= i < PyList_GET_SIZE(bucket) by 4: 
403  422  tmp = <object>PyList_GET_ITEM(bucket, i) 
404   if <Py_ssize_t>tmp == h1: 
 423  if <size_t>tmp == h1: 
405  424  tmp = <object>PyList_GET_ITEM(bucket, i+1) 
406   if <Py_ssize_t>tmp == h2: 
 425  if <size_t>tmp == h2: 
407  426  tmp = <object>PyList_GET_ITEM(bucket, i+2) 
408   if <Py_ssize_t>tmp == h3: 
 427  if <size_t>tmp == h3: 
409  428  bucket[i+3] = value 
410  429  return 
411  430  PyList_Append(bucket, h1) 
… 
… 

448  467  k1, k2, k3 = k 
449  468  except (TypeError,ValueError): 
450  469  raise KeyError, k 
451   cdef Py_ssize_t h = (<Py_ssize_t><void *>k1 + 13*<Py_ssize_t><void *>k2 ^ 503*<Py_ssize_t><void *>k3) 
452   #if h < 0: h = h 
 470  cdef size_t h = (<size_t><void *>k1 + 13*<size_t><void *>k2 ^ 503*<size_t><void *>k3) 
453  471  cdef Py_ssize_t i 
454  472  cdef list bucket = <object>PyList_GET_ITEM(self.buckets, h % PyList_GET_SIZE(self.buckets)) 
455  473  for i from 0 <= i < PyList_GET_SIZE(bucket) by 4: 
456   if <Py_ssize_t><object>PyList_GET_ITEM(bucket, i) == <Py_ssize_t><void *>k1 and \ 
457   <Py_ssize_t><object>PyList_GET_ITEM(bucket, i+1) == <Py_ssize_t><void *>k2 and \ 
458   <Py_ssize_t><object>PyList_GET_ITEM(bucket, i+2) == <Py_ssize_t><void *>k3: 
 474  if <size_t><object>PyList_GET_ITEM(bucket, i) == <size_t><void *>k1 and \ 
 475  <size_t><object>PyList_GET_ITEM(bucket, i+1) == <size_t><void *>k2 and \ 
 476  <size_t><object>PyList_GET_ITEM(bucket, i+2) == <size_t><void *>k3: 
459  477  del bucket[i:i+4] 
460  478  self._size = 1 
461  479  return 
… 
… 

485  503  buckets = next_odd_prime(2*len(self.buckets)) 
486  504  cdef list old_buckets = self.buckets 
487  505  cdef list bucket 
488   cdef Py_ssize_t i, h 
 506  cdef Py_ssize_t i 
 507  cdef size_t h 
489  508  self.buckets = [[] for i from 0 <= i < buckets] 
490   cdef Py_ssize_t k1,k2,k3 
 509  cdef size_t k1,k2,k3 
491  510  cdef object v 
492  511  for bucket in old_buckets: 
493  512  for i from 0 <= i < PyList_GET_SIZE(bucket) by 4: 
494   k1 = <Py_ssize_t><object>PyList_GET_ITEM(bucket,i) 
495   k2 = <Py_ssize_t><object>PyList_GET_ITEM(bucket,i+1) 
496   k3 = <Py_ssize_t><object>PyList_GET_ITEM(bucket,i+2) 
497   v = <object>PyList_GET_ITEM(bucket,i+3) 
498   h = (k1 + 13*k2 ^ 503*k3) % buckets # the new hash 
499   self.buckets[h] += [k1,k2,k3,v] 
 513  k1 = <size_t><object>PyList_GET_ITEM(bucket, i) 
 514  k2 = <size_t><object>PyList_GET_ITEM(bucket, i+1) 
 515  k3 = <size_t><object>PyList_GET_ITEM(bucket, i+2) 
 516  v = <object>PyList_GET_ITEM(bucket, i+3) 
 517  h = (k1 + 13*k2 ^ 503*k3) 
 518  self.buckets[h % buckets] += [k1,k2,k3,v] 
500  519  
501  520  def iteritems(self): 
502  521  """ 
… 
… 

567  586  while self.bucket_iter is None: 
568  587  self.bucket_iter = self.buckets.next() 
569  588  self.bucket_iter = iter(self.bucket_iter) 
570   cdef Py_ssize_t k1,k2,k3 
 589  cdef size_t k1,k2,k3 
571  590  try: 
572  591  k1 = self.bucket_iter.next() 
573  592  k2 = self.bucket_iter.next() 