WeakValueDictionary.st
branchjv
changeset 20205 03e626304d06
parent 19811 65fec19facb0
parent 20169 79a892cdfff9
child 25411 248600ba8fd9
--- a/WeakValueDictionary.st	Fri Jul 29 21:39:49 2016 +0100
+++ b/WeakValueDictionary.st	Fri Jul 29 21:40:03 2016 +0100
@@ -81,7 +81,7 @@
         ].
     ].
 
-    ret class == SmallInteger ifTrue:[
+    (ret isNil or:[ret class == SmallInteger]) ifTrue:[
         ret := somethingRespondingToValue value
     ].
     ^ ret
@@ -110,7 +110,7 @@
         ].
     ].
 
-    val class == SmallInteger ifTrue:[
+    (val isNil or:[val class == SmallInteger]) ifTrue:[
         self error:'WeakValueDictionary: invalid value'.
     ].
 
@@ -125,7 +125,7 @@
 
     |val|
 
-    anObject class == SmallInteger ifTrue:[
+    (anObject isNil or:[anObject class == SmallInteger]) ifTrue:[
         self error:'WeakValueDictionary: invalid value'.
     ].
 
@@ -145,6 +145,35 @@
     "Modified: 29.1.1997 / 15:08:45 / cg"
 !
 
+removeIdentityValue:aValue ifAbsent:aBlock 
+    "remove the association under aValue from the collection,
+     return the key previously stored there.
+     If it was not in the collection return the result
+     from evaluating aBlock.
+
+     Redefined to avoid synchronization problems, in case
+     of interrupts (otherwise, there could be some other operation
+     on the receiver done by another process, which garbles my contents)."
+    
+    |ret|
+
+    (aValue isNil or:[ aValue class == SmallInteger ]) ifTrue:[
+        ^ aBlock value.
+    ].
+    OperatingSystem blockInterrupts ifTrue:[
+        "/ already blocked
+        ret := super removeIdentityValue:aValue ifAbsent:aBlock
+    ] ifFalse:[
+        [
+            ret := super removeIdentityValue:aValue ifAbsent:aBlock
+        ] ensure:[ OperatingSystem unblockInterrupts. ].
+    ].
+    ^ ret.
+
+    "Created: 6.5.1996 / 14:47:37 / stefan"
+    "Modified: 8.5.1996 / 14:54:09 / stefan"
+!
+
 removeKey:aKey ifAbsent:aBlock
     "remove the association under aKey from the collection,
      return the value previously stored there.
@@ -157,16 +186,28 @@
 
     |ret|
 
-    [
-	ret := super removeKey:aKey ifAbsent:aBlock
-    ] valueUninterruptably.
+    OperatingSystem blockInterrupts ifTrue:[
+        "/ already blocked
+        ret := super removeKey:aKey ifAbsent:aBlock
+    ] ifFalse:[
+        [
+            ret := super removeKey:aKey ifAbsent:aBlock
+        ] ensure:[
+            OperatingSystem unblockInterrupts.
+        ].
+    ].
+
+    (ret isNil or:[ret class == SmallInteger]) ifTrue:[
+        ^ aBlock value.
+    ].
+
     ^ ret
 
     "Modified: 6.5.1996 / 12:44:07 / stefan"
     "Created: 6.5.1996 / 14:47:37 / stefan"
 !
 
-removeValue:aKey ifAbsent:aBlock
+removeValue:aValue ifAbsent:aBlock
     "remove the association under aValue from the collection,
      return the key previously stored there.
      If it was not in the collection return the result
@@ -178,9 +219,21 @@
 
     |ret|
 
-    [
-	ret := super removeValue:aKey ifAbsent:aBlock
-    ] valueUninterruptably.
+    (aValue isNil or:[aValue class == SmallInteger]) ifTrue:[
+        ^ aBlock value.
+    ].
+
+    OperatingSystem blockInterrupts ifTrue:[
+        "/ already blocked
+        ret := super removeValue:aValue ifAbsent:aBlock
+    ] ifFalse:[
+        [
+            ret := super removeValue:aValue ifAbsent:aBlock
+        ] ensure:[
+            OperatingSystem unblockInterrupts.
+        ].
+    ].
+
     ^ ret.
 
     "Created: 6.5.1996 / 14:47:37 / stefan"
@@ -202,6 +255,26 @@
     "Created: 7.1.1997 / 16:59:30 / stefan"
 ! !
 
+!WeakValueDictionary methodsFor:'enumerating'!
+
+do:aBlock
+    super do:[:eachValue|
+        "garbage collected values will change to nil or a SmallInteger"
+        (eachValue notNil and:[eachValue class ~~ SmallInteger]) ifTrue:[
+            aBlock value:eachValue.
+        ].
+    ].
+!
+
+keysAndValuesDo:aBlock
+    super keysAndValuesDo:[:eachKey :eachValue|
+        "garbage collected values will change to a SmallInteger"
+        eachValue class ~~ SmallInteger ifTrue:[
+            aBlock value:eachKey value:eachValue.
+        ].
+    ].
+! !
+
 !WeakValueDictionary methodsFor:'private'!
 
 clearDeadSlots
@@ -232,8 +305,10 @@
      and shrink if it makes sense.
      Definition of 'too empty' is: 'filled less than 12.5% (i.e. 1/8th)'"
 
-    self clearDeadSlots.
-    super possiblyShrink
+    keyArray basicSize > 56 ifTrue:[
+        self clearDeadSlots.
+        super possiblyShrink.
+    ].
 !
 
 valueContainerOfSize:n
@@ -255,28 +330,44 @@
     "redefined to block interrupts
      (avoid change of the dictionary while accessing)"
 
-    |val|
+    |ret wasBlocked|
 
-    [
-	val := super includes:anObject.
-    ] valueUninterruptably.
-    ^ val
+    (anObject isNil or:[anObject class == SmallInteger]) ifTrue:[
+        "Integers cannot be stored into a WeakValueDictionary"
+        ^ false.
+    ].
+
+    wasBlocked := OperatingSystem blockInterrupts.
+    ret := super includes:anObject.
+    wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
+     ^ ret
 
     "Modified: 6.5.1996 / 12:22:26 / stefan"
     "Modified: 1.7.1997 / 10:45:52 / cg"
     "Created: 1.7.1997 / 15:41:14 / cg"
 !
 
-includesKey:key
+includesIdentical:anObject
     "redefined to block interrupts
      (avoid change of the dictionary while accessing)"
 
-    |val|
+    |ret wasBlocked|
+
+    (anObject isNil or:[anObject class == SmallInteger]) ifTrue:[
+        "Integers cannot be stored into a WeakValueDictionary"
+        ^ false.
+    ].
 
-    [
-	val := super includesKey:key.
-    ] valueUninterruptably.
-    ^ val
+    wasBlocked := OperatingSystem blockInterrupts.
+    ret := super includesIdentical:anObject.
+    wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
+     ^ ret
+!
+
+includesKey:key
+    "redefined to check for already collected values"
+
+    ^ (self at:key ifAbsent:DeletedEntry) ~~ DeletedEntry.
 
     "Modified: 6.5.1996 / 12:22:26 / stefan"
     "Modified: 1.7.1997 / 10:45:52 / cg"