@@ -303,6 +303,83 @@ def test_del_dictitem_by_exact_value(D, value, h):
303
303
"""
304
304
return del_dictitem_by_exact_value(< PyDictObject * > D, < PyObject * > value, h)
305
305
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
+
306
383
cdef class WeakValueDictionary(dict ):
307
384
"""
308
385
IMPLEMENTATION:
@@ -396,6 +473,7 @@ cdef class WeakValueDictionary(dict):
396
473
....: assert D1 == D2
397
474
398
475
"""
476
+ cdef __weakref__
399
477
cdef callback
400
478
cdef int _guard_level
401
479
cdef list _pending_removals
@@ -422,24 +500,14 @@ cdef class WeakValueDictionary(dict):
422
500
423
501
"""
424
502
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 )
440
504
self ._guard_level = 0
441
505
self ._pending_removals = []
442
506
self ._iteration_context = _IterationContext(self )
507
+ try :
508
+ data= data.iteritems()
509
+ except AttributeError :
510
+ pass
443
511
for k,v in data:
444
512
self [k] = v
445
513
0 commit comments