Skip to content

Commit 9bb9241

Browse files
committed
trac #15432: use a callback class object holding a weak reference for sage.misc.weak_dict.WeakValueDictionary
1 parent f36d14a commit 9bb9241

File tree

1 file changed

+83
-15
lines changed

1 file changed

+83
-15
lines changed

src/sage/misc/weak_dict.pyx

+83-15
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,83 @@ def test_del_dictitem_by_exact_value(D, value, h):
303303
"""
304304
return del_dictitem_by_exact_value(<PyDictObject *>D, <PyObject *>value, h)
305305

306+
cdef class WeakValueDictEraser:
307+
"""
308+
Erases items from a :class:`sage.misc.weak_dict.WeakValueDictionary` when
309+
a weak reference becomes invalid.
310+
311+
This is of internal use only. Instances of this class will be passed as a
312+
callback function when creating a weak reference.
313+
314+
EXAMPLES::
315+
316+
sage: from sage.misc.weak_dict import WeakValueDictionary
317+
sage: v = frozenset([1])
318+
sage: D = WeakValueDictionary({1 : v})
319+
sage: len(D)
320+
1
321+
sage: del v
322+
sage: len(D)
323+
0
324+
325+
AUTHOR:
326+
327+
- Nils Bruin (2013-11)
328+
"""
329+
cdef D
330+
def __init__(self, D):
331+
"""
332+
INPUT:
333+
334+
A :class:`sage.misc.weak_dict.WeakValueDictionary`.
335+
336+
EXAMPLES::
337+
338+
sage: v = frozenset([1])
339+
sage: D = sage.misc.weak_dict.WeakValueDictionary({ 1 : v })
340+
sage: len(D)
341+
1
342+
sage: del v
343+
sage: len(D) #indirect doctest
344+
0
345+
"""
346+
self.D = PyWeakref_NewRef(D,None)
347+
def __call__(self, r):
348+
"""
349+
INPUT:
350+
351+
A weak reference with key.
352+
353+
When this is called with a weak reference ``r``, then an entry from the
354+
dictionary pointed to by `self.D` is removed that has ``r`` as a value
355+
identically, stored under a key with hash `r.key`. If no such key
356+
exists, or if the dictionary itself doesn't exist any more, then nothing
357+
happens.
358+
359+
If the dictionary has an iterator active on it then the object is
360+
queued for removal when all iterators have concluded.
361+
362+
EXAMPLES::
363+
364+
sage: v = frozenset([1])
365+
sage: D = sage.misc.weak_dict.WeakValueDictionary({ 1 : v })
366+
sage: len(D)
367+
1
368+
sage: del v
369+
sage: len(D) #indirect doctest
370+
0
371+
"""
372+
cdef WeakValueDictionary D = <object> PyWeakref_GetObject(<PyObject*> self.D)
373+
if D is None:
374+
return
375+
#The situation is the following:
376+
#in the underlying dictionary, we have stored a KeyedRef r
377+
#under a key k. The attribute r.key is the hash of k.
378+
if D._guard_level:
379+
D._pending_removals.append(r)
380+
else:
381+
del_dictitem_by_exact_value(<PyDictObject *>D, <PyObject *>r, r.key)
382+
306383
cdef class WeakValueDictionary(dict):
307384
"""
308385
IMPLEMENTATION:
@@ -396,6 +473,7 @@ cdef class WeakValueDictionary(dict):
396473
....: assert D1 == D2
397474
398475
"""
476+
cdef __weakref__
399477
cdef callback
400478
cdef int _guard_level
401479
cdef list _pending_removals
@@ -422,24 +500,14 @@ cdef class WeakValueDictionary(dict):
422500
423501
"""
424502
dict.__init__(self)
425-
# Define a callback function. In contrast to what is done in Python's
426-
# weakref.WeakValueDictionary, we use a closure and not a weak
427-
# reference to refer to self. Reason: We trust that we will not create
428-
# sub-classes of keyed references or weak value dictionaries providing
429-
# a __del__ method.
430-
def callback(r):
431-
#The situation is the following:
432-
#in the underlying dictionary, we have stored a KeyedRef r
433-
#under a key k. The attribute r.key is the hash of k.
434-
cdef WeakValueDictionary cself = self
435-
if cself._guard_level:
436-
cself._pending_removals.append(r)
437-
else:
438-
del_dictitem_by_exact_value(<PyDictObject *>cself, <PyObject *>r, r.key)
439-
self.callback = callback
503+
self.callback = WeakValueDictEraser(self)
440504
self._guard_level = 0
441505
self._pending_removals = []
442506
self._iteration_context = _IterationContext(self)
507+
try:
508+
data=data.iteritems()
509+
except AttributeError:
510+
pass
443511
for k,v in data:
444512
self[k] = v
445513

0 commit comments

Comments
 (0)