Ticket #715: trac_715_local_refcache.patch

File trac_715_local_refcache.patch, 4.4 KB (added by SimonKing, 7 years ago)

Keep track of references in a local dictionary

  • sage/structure/coerce_dict.pxd

    # HG changeset patch
    # User Simon King <simon.king@uni-jena.de>
    # Date 1345539136 -7200
    # Node ID 3cc26d30933504b7957811be2b5ee8b7ac9a3dac
    # Parent  550c6017fb4decf4fdef553682da35972f041634
    #715: Store references locally in a TripleDict
    
    diff --git a/sage/structure/coerce_dict.pxd b/sage/structure/coerce_dict.pxd
    a b  
    11cdef class TripleDict:
    22    cdef Py_ssize_t _size
    33    cdef buckets
     4    cdef dict _refcache
    45    cdef double threshold
    56    cdef TripleDictEraser eraser
    67    cdef get(self, object k1, object k2, object k3)
  • sage/structure/coerce_dict.pyx

    diff --git a/sage/structure/coerce_dict.pyx b/sage/structure/coerce_dict.pyx
    a b  
    1818# removing dead references from the cache
    1919############################################
    2020
    21 cdef dict _refcache = {}
    22 
    2321cdef class TripleDictEraser:
    2422    """
    2523    Erases items from a :class:`TripleDict` when a weak reference becomes
     
    108106                del bucket[i:i+4]
    109107                self.D._size -= 1
    110108                break
    111         cdef list L = _refcache[k1,k2,k3]
    112         del L[L.index(r)]
     109        try:
     110            self.D._refcache.__delitem__((k1,k2,k3))
     111        except KeyError:
     112            pass
    113113
    114114cdef class TripleDict:
    115115    """
     
    258258        self.buckets = [[] for i from 0 <= i <  size]
    259259        self._size = 0
    260260        self.eraser = TripleDictEraser(self)
     261        self._refcache = {}
    261262        if data is not None:
    262263            for (k1,k2,k3), v in data.iteritems():
    263264                self.set(k1,k2,k3, v)
     
    375376        return self.get(k1, k2, k3)
    376377
    377378    cdef get(self, object k1, object k2, object k3):
    378         cdef size_t h = (<size_t><void *>k1 + 13*<size_t><void *>k2 ^ 503*<size_t><void *>k3)
     379        cdef size_t h1,h2,h3
     380        h1 = <size_t><void *>k1
     381        h2 = <size_t><void *>k2
     382        h3 = <size_t><void *>k3
     383        cdef object r1,r2,r3
     384        try:
     385            r1,r2,r3 = self._refcache[h1,h2,h3]
     386        except KeyError:
     387            raise KeyError, (k1,k2,k3)
     388        if (isinstance(r1,KeyedRef) and r1() is None) or \
     389           (isinstance(r2,KeyedRef) and r2() is None) or \
     390           (isinstance(r3,KeyedRef) and r3() is None):
     391            raise KeyError, (k1,k2,k3)
     392        cdef size_t h = (h1 + 13*h2 ^ 503*h3)
    379393        cdef Py_ssize_t i
    380394        cdef list all_buckets = self.buckets
    381395        cdef list bucket = <object>PyList_GET_ITEM(all_buckets, h % PyList_GET_SIZE(all_buckets))
     
    432446        PyList_Append(bucket, h3)
    433447        PyList_Append(bucket, value)
    434448        try:
    435             PyList_Append(_refcache.setdefault((h1 , h2, h3), []),
    436                 KeyedRef(k1,self.eraser,(h1, h2, h3)))
     449            ref1 = KeyedRef(k1,self.eraser,(h1, h2, h3))
    437450        except TypeError:
    438             PyList_Append(_refcache.setdefault((h1, h2, h3), []), k1)
     451            ref1 = k1
    439452        if k2 is not k1:
    440453            try:
    441                 PyList_Append(_refcache.setdefault((h1 , h2, h3), []),
    442                     KeyedRef(k2,self.eraser,(h1, h2, h3)))
     454                ref2 = KeyedRef(k2,self.eraser,(h1, h2, h3))
    443455            except TypeError:
    444                 PyList_Append(_refcache.setdefault((h1, h2, h3), []), k2)
    445         if k3 is not k1 and k3 is not k2:
     456                ref2 = k2
     457        else:
     458            ref2 = None
     459        if k3 is not k2 or k3 is not k1:
    446460            try:
    447                 PyList_Append(_refcache.setdefault((h1 , h2, h3), []),
    448                     KeyedRef(k3,self.eraser,(h1, h2, h3)))
     461                ref3 = KeyedRef(k3,self.eraser,(h1, h2, h3))
    449462            except TypeError:
    450                 PyList_Append(_refcache.setdefault((h1, h2, h3), []),k3)
     463                ref3 = k3
     464        else:
     465            ref3 = None
     466        self._refcache[h1,h2,h3] = (ref1,ref2,ref3)
    451467        self._size += 1
    452468
    453469    def __delitem__(self, k):
     
    467483            k1, k2, k3 = k
    468484        except (TypeError,ValueError):
    469485            raise KeyError, k
     486        try:
     487            del self._refcache[<size_t><void *>k1,<size_t><void *>k2,<size_t><void *>k3]
     488        except KeyError:
     489            raise KeyError, k
    470490        cdef size_t h = (<size_t><void *>k1 + 13*<size_t><void *>k2 ^ 503*<size_t><void *>k3)
    471491        cdef Py_ssize_t i
    472492        cdef list bucket = <object>PyList_GET_ITEM(self.buckets, h % PyList_GET_SIZE(self.buckets))