Ticket #715: trac_715_safer.patch

File trac_715_safer.patch, 8.1 KB (added by SimonKing, 7 years ago)

Fix some issues: Test validity of references when setting items; use the new "yield" statement in Cython for iteration.

  • sage/structure/coerce.pxd

    # HG changeset patch
    # User Simon King <simon.king@uni-jena.de>
    # Date 1345718778 -7200
    # Node ID 9cc4d78afa2a1d5dcddcf9118c006dc37295c623
    # Parent  3cc26d30933504b7957811be2b5ee8b7ac9a3dac
    #715: Fix some issues pointed out by the reviewer. Remove TripleDictIter.
    
    diff --git a/sage/structure/coerce.pxd b/sage/structure/coerce.pxd
    a b  
    44from parent cimport Parent
    55from sage.categories.action cimport Action
    66
    7 from coerce_dict cimport TripleDict, TripleDictIter
     7from coerce_dict cimport TripleDict
    88
    99cdef class CoercionModel_cache_maps(CoercionModel):
    1010    # This MUST be a mapping to tuples, where each
  • sage/structure/coerce_dict.pxd

    diff --git a/sage/structure/coerce_dict.pxd b/sage/structure/coerce_dict.pxd
    a b  
    77    cdef get(self, object k1, object k2, object k3)
    88    cdef set(self, object k1, object k2, object k3, value)
    99   
    10 cdef class TripleDictIter:
    11     cdef TripleDict pairs
    12     cdef buckets, bucket_iter
    13 
    1410cdef class TripleDictEraser:
    1511    cdef TripleDict D
  • sage/structure/coerce_dict.pyx

    diff --git a/sage/structure/coerce_dict.pyx b/sage/structure/coerce_dict.pyx
    a b  
    1010
    1111include "../ext/python_list.pxi"
    1212
    13 from sage.misc.constant_function import ConstantFunction
    1413from weakref import KeyedRef
    1514
    1615############################################
     
    183182        ...
    184183        KeyError: 'a'
    185184
    186     The following illustrates why even sizes are bad::
     185    The following illustrates why even sizes are bad (setting the threshold
     186    zero, so that no beneficial resizing happens)::
    187187
    188         sage: L = TripleDict(4, L)
     188        sage: L = TripleDict(4, L, threshold=0)
    189189        sage: L.stats()
    190190        (0, 250.25, 1001)
    191191        sage: L.bucket_lens()
     
    240240    - Simon King, 2012-01
    241241    """
    242242
    243     def __init__(self, size, data=None, threshold=0):
     243    def __init__(self, size, data=None, threshold=0.7):
    244244        """
    245245        Create a special dict using triples for keys.
    246246
     
    302302            sage: L.stats() # random
    303303            (0, 0.03325573661456601, 1)
    304304
    305             sage: L = TripleDict(1)
     305        In order to have a test that isn't random, we use parameters
     306        that should not be used in real applications::
     307
     308            sage: L = TripleDict(1, threshold=0)
    306309            sage: for i in range(100): L[i,i,i] = None
    307310            sage: L.stats()
    308311            (100, 100.0, 100)
     
    329332        EXAMPLES::
    330333
    331334            sage: from sage.structure.coerce_dict import TripleDict
    332             sage: L = TripleDict(37)
     335            sage: L = TripleDict(37, threshold=0)
    333336            sage: for i in range(100): L[i,i,i] = None
    334337            sage: L.bucket_lens() # random
    335338            [3, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 3, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4]
    336339            sage: sum(L.bucket_lens())
    337340            100
    338341
    339             sage: L = TripleDict(1)
     342        In order to have a test that isn't random, we use parameters
     343        that should not be used in real applications::
     344
     345            sage: L = TripleDict(1, threshold=0)
    340346            sage: for i in range(100): L[i,i,i] = None
    341347            sage: L.bucket_lens()
    342348            [100]
     
    439445                if <size_t>tmp == h2:
    440446                    tmp = <object>PyList_GET_ITEM(bucket, i+2)
    441447                    if <size_t>tmp == h3:
     448                        # Test whether the old references are still active
     449                        r1,r2,r3 = <tuple>(self._refcache[h1,h2,h3])
     450                        if (isinstance(r1,KeyedRef) and r1() is None) or \
     451                           (isinstance(r2,KeyedRef) and r2() is None) or \
     452                           (isinstance(r3,KeyedRef) and r3() is None):
     453                            del bucket [i:i+4]
     454                            self._size -= 1
     455                            break
    442456                        bucket[i+3] = value
    443457                        return
    444458        PyList_Append(bucket, h1)
     
    484498        except (TypeError,ValueError):
    485499            raise KeyError, k
    486500        try:
     501            r1,r2,r3 = self._refcache[<size_t><void *>k1,<size_t><void *>k2,<size_t><void *>k3]
     502        except KeyError:
     503            raise KeyError, k
     504        if (isinstance(r1,KeyedRef) and r1() is None) or \
     505           (isinstance(r2,KeyedRef) and r2() is None) or \
     506           (isinstance(r3,KeyedRef) and r3() is None):
     507            raise KeyError, k
     508        try:
    487509            del self._refcache[<size_t><void *>k1,<size_t><void *>k2,<size_t><void *>k3]
    488510        except KeyError:
     511            # This is to cope with a potential racing condition - if garbage
     512            # collection and weakref callback happens right between the
     513            # "if (isinstance(r1,..." and the "del", then the previously
     514            # existing entry might already be gone.
    489515            raise KeyError, k
    490516        cdef size_t h = (<size_t><void *>k1 + 13*<size_t><void *>k2 ^ 503*<size_t><void *>k3)
    491517        cdef Py_ssize_t i
     
    547573            sage: list(L.iteritems())
    548574            [((1, 2, 3), None)]
    549575        """
    550         return TripleDictIter(self)
     576        cdef list bucket
     577        cdef size_t i, h1,h2,h3
     578        # We test whether the references are still valid.
     579        # However, we must not delete them, since we are
     580        # iterating.
     581        for bucket in self.buckets:
     582            for i from 0<=i<len(bucket) by 4:
     583                h1,h2,h3 = bucket[i:i+3]
     584                try:
     585                    r1,r2,r3 = self._refcache[h1,h2,h3]
     586                except KeyError:
     587                    # That can only happen under a race condition.
     588                    # Anyway, it means the item is not there.
     589                    continue
     590                if isinstance(r1, KeyedRef):
     591                    r1 = r1()
     592                    if r1 is None:
     593                        continue
     594                if isinstance(r2, KeyedRef):
     595                    r2 = r2()
     596                    if r2 is None:
     597                        continue
     598                if isinstance(r3, KeyedRef):
     599                    r3 = r3()
     600                    if r3 is None:
     601                        continue
     602                yield (r1,r2,r3), <object>PyList_GET_ITEM(bucket,i+3)
    551603
    552604    def __reduce__(self):
    553605        """
     
    566618        """
    567619        return TripleDict, (len(self.buckets), dict(self.iteritems()), self.threshold)
    568620
    569 cdef class TripleDictIter:
    570     def __init__(self, pairs):
    571         """
    572         EXAMPLES::
    573 
    574             sage: from sage.structure.coerce_dict import TripleDict, TripleDictIter
    575             sage: L = TripleDict(31)
    576             sage: L[1,2,3] = None
    577             sage: L.iteritems().next()
    578             ((1, 2, 3), None)
    579         """
    580         self.pairs = pairs
    581         self.buckets = iter(self.pairs.buckets)
    582 
    583     def __iter__(self):
    584         """
    585         EXAMPLES::
    586 
    587             sage: from sage.structure.coerce_dict import TripleDict, TripleDictIter
    588             sage: L = TripleDict(31)
    589             sage: L[1,2,3] = None
    590             sage: iter(L.iteritems()).next()
    591             ((1, 2, 3), None)
    592         """
    593         return self
    594 
    595     def __next__(self):
    596         """
    597         EXAMPLES::
    598 
    599             sage: from sage.structure.coerce_dict import TripleDict, TripleDictIter
    600             sage: L = TripleDict(31)
    601             sage: L[1,2,3] = None
    602             sage: L[3,2,1] = None
    603             sage: sorted(L.iteritems())
    604             [((1, 2, 3), None), ((3, 2, 1), None)]
    605         """
    606         while self.bucket_iter is None:
    607             self.bucket_iter = self.buckets.next()
    608         self.bucket_iter = iter(self.bucket_iter)
    609         cdef size_t k1,k2,k3
    610         try:
    611             k1 = self.bucket_iter.next()
    612             k2 = self.bucket_iter.next()
    613             k3 = self.bucket_iter.next()
    614             value = self.bucket_iter.next()
    615             return ((<object><PyObject *>k1, <object><PyObject *>k2,
    616                      <object><PyObject *>k3), value)
    617         except StopIteration:
    618             self.bucket_iter = None
    619             return self.next()
    620 
    621 
    622621cdef long next_odd_prime(long n):
    623622    if n % 2 == 0:
    624623        n -= 1