KeyedCollection.st
changeset 21653 baee5890dca8
parent 21649 4a09b7965b34
child 21655 058cafb6c2f6
--- a/KeyedCollection.st	Thu Mar 16 16:50:14 2017 +0100
+++ b/KeyedCollection.st	Thu Mar 16 21:30:11 2017 +0100
@@ -130,12 +130,41 @@
 
 !KeyedCollection methodsFor:'accessing'!
 
-associationAt:key 
+associationAt:aKey 
     "return an association consisting of aKey and the element indexed 
      by aKey - 
      report an error, if no element is stored under aKey."
 
-    ^ Association key:key value:(self at:key)
+    ^ self associationAt:aKey ifAbsent:[self errorKeyNotFound:aKey]
+
+    "Modified: / 16-03-2017 / 17:19:52 / stefan"
+!
+
+associationAt:aKey ifAbsent:exceptionBlock
+    "return an association consisting of aKey and the element indexed by aKey -
+     return result of exceptionBlock if no element is stored under aKey.
+     Warning: this is a comatibility interface only, with a different semantic as
+              the original ST80 implementation. The returned assoc is created on the fly,
+              and not the one stored in the receiver (there are not assocs there)"
+
+    |value|
+
+    value := self at:aKey ifAbsent:[^ exceptionBlock value].
+    ^ Association key:aKey value:value.
+
+    "Created: / 16-03-2017 / 17:17:05 / stefan"
+!
+
+associations
+    "return an ordered collection containing the receiver's associations."
+
+    |coll|
+
+    coll := OrderedCollection new.
+    self associationsDo:[:assoc | coll add:assoc].
+    ^ coll
+
+    "Created: / 16-03-2017 / 17:30:47 / stefan"
 !
 
 at:key
@@ -156,6 +185,83 @@
     "Created: / 19.6.1998 / 00:48:23 / cg"
 !
 
+at:aKey ifAbsent:default update:aBlock
+    "update the element stored under aKey with the result from
+     evaluating aBlock with the previous stored value as argument, or with default,
+     if there was no such key initially.
+     Return the new value stored."
+
+    ^ self at:aKey put:(aBlock value:(self at:aKey ifAbsent:default))
+
+    "Created: / 16-03-2017 / 17:28:15 / stefan"
+!
+
+at:aKey ifAbsentPut:valueBlock
+    "return the element indexed by aKey if present,
+     if not present, store the result of evaluating valueBlock
+     under aKey and return it.
+     WARNING: do not add elements while iterating over the receiver.
+              Iterate over a copy to do this."
+
+    ^ self at:aKey ifAbsent:[self at:aKey put:valueBlock value].
+
+    "Created: / 16-03-2017 / 17:23:07 / stefan"
+!
+
+at:aKey ifPresent:aBlock
+    "try to retrieve the value stored at aKey.
+     If there is nothing stored under this key, do nothing.
+     Otherwise, evaluate aBlock, passing the retrieved value as argument."
+
+    |v|
+
+    v := self at:aKey ifAbsent:[^ nil].
+    ^ aBlock value:v.
+
+    "Created: / 16-03-2017 / 17:11:27 / stefan"
+!
+
+at:aKey put:anObject
+    "add the argument anObject under key, aKey to the receiver.
+     Return anObject (sigh).
+     WARNING: do not add elements while iterating over the receiver.
+              Iterate over a copy to do this."
+
+    ^ self subclassResponsibility
+
+    "Created: / 16-03-2017 / 17:33:12 / stefan"
+!
+
+at:aKey put:anObject ifPresent:aBlock
+    "if the receiver contains an element stored under aKey,
+     retrieve it and evaluate aBlock passing the element as argument,
+     return the blocks value.
+     If not, store aValue under the key.
+     Use this with an error-reporting block, to ensure that no keys are reused"
+
+    |value isAbsent|
+
+    value := self at:aKey ifAbsent:[isAbsent := true. self at:aKey put:anObject].
+    isAbsent notNil ifTrue:[
+        ^ value.
+    ].
+
+    ^ aBlock value:value.
+
+    "Created: / 16-03-2017 / 17:38:00 / stefan"
+!
+
+at:aKey update:aBlock
+    "update the element stored under aKey with the result from
+     evaluating aBlock with the previous stored value as argument.
+     Report an error if there was no such key initially.
+     Return the new value stored."
+
+    ^ self at:aKey put:(aBlock value:(self at:aKey))
+
+    "Created: / 16-03-2017 / 17:29:22 / stefan"
+!
+
 keyAtEqualValue:value
     "return the key under which value is stored.
      Raise an error if not found.
@@ -215,13 +321,14 @@
      Raise an error if not found.
      This is a slow access, since the receiver is searched sequentially.
      NOTICE:
-        The value is searched using identity compare.
-        use #keyAtEqualValue:ifAbsent: to compare for equality."
+        The value is searched using equality compare"
 
-    ^ self keyAtIdenticalValue:value.
+
+    ^ self keyAtEqualValue:value.
 
     "Created: / 19-06-1998 / 00:49:16 / cg"
     "Modified (comment): / 07-02-2017 / 11:13:29 / cg"
+    "Modified (comment): / 16-03-2017 / 18:00:28 / stefan"
 !
 
 keyAtValue:value ifAbsent:exceptionBlock
@@ -229,13 +336,14 @@
      If not found, return the value from evaluating exceptionBlock.
      This is a slow access, since the receiver is searched sequentially.
      NOTICE:
-        The value is searched using identity compare;
-        use #keyAtEqualValue:ifAbsent: to compare for equality."
+        The value is searched using equality compare"
 
-    ^ self keyAtIdenticalValue:value ifAbsent:exceptionBlock.
+
+    ^ self keyAtEqualValue:value ifAbsent:exceptionBlock.
 
     "Created: / 19-06-1998 / 00:50:34 / cg"
     "Modified: / 07-02-2017 / 11:13:20 / cg"
+    "Modified (comment): / 16-03-2017 / 18:00:37 / stefan"
 !
 
 keys
@@ -263,19 +371,6 @@
     "Created: / 19.6.1998 / 00:56:24 / cg"
 !
 
-findFirstKey:aBlock
-    "find and return the first key, for which evaluation of the argument, aBlock
-     returns true; return nil if none is detected."
-
-    self keysDo:[:key |
-        (aBlock value:key) ifTrue:[^ key].
-    ].
-    ^ nil
-
-    "Created: 8.10.1996 / 22:01:31 / cg"
-    "Modified: 8.10.1996 / 22:02:03 / cg"
-!
-
 keysAndValuesDo:aBlock
     "evaluate aBlock for each key and value"
 
@@ -307,6 +402,41 @@
     "Created: / 19.6.1998 / 00:53:58 / cg"
 ! !
 
+!KeyedCollection methodsFor:'searching'!
+
+findFirst:aBlock ifNone:exceptionValue
+    "find the index of the first element, for which evaluation of the argument, aBlock returns true;
+     return its index or the value from exceptionValue if none detected.
+     This is much like #detect:ifNone:, however, here an INDEX is returned,
+     while #detect:ifNone: returns the element.
+
+     Here we return the first key for which aBlock matches the value.
+     Note that there is no order in a Dictionary, so any element is first."
+
+    self keysAndValuesDo:[:eachKey :eachValue| (aBlock value:eachValue) ifTrue:[^ eachKey]].
+    ^ exceptionValue value.
+
+    "
+        (KeyValueList withKeys:#('a' 'b' 'c') andValues:#('bla' 'hello' 'hallo'))
+            findFirst:[:v| v first = $h].
+    "
+
+    "Created: / 16-03-2017 / 17:46:02 / stefan"
+!
+
+findFirstKey:aBlock
+    "find and return the first key, for which evaluation of the argument, aBlock
+     returns true; return nil if none is detected."
+
+    self keysDo:[:key |
+        (aBlock value:key) ifTrue:[^ key].
+    ].
+    ^ nil
+
+    "Created: 8.10.1996 / 22:01:31 / cg"
+    "Modified: 8.10.1996 / 22:02:03 / cg"
+! !
+
 !KeyedCollection methodsFor:'testing'!
 
 includesIdenticalKey:aKey