forked from SeasideSt/Grease
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGROrderedMultiMap.class.st
More file actions
83 lines (73 loc) · 2.39 KB
/
GROrderedMultiMap.class.st
File metadata and controls
83 lines (73 loc) · 2.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
"
I am an implementation of an ordered multi-map. I allow multiple values to be associated with the same key and maintain the order of addition. #at: and its derivatives all operate on the first matching key, while #allAt: returns the complete list of values for a key in the order they were added.
"
Class {
#name : #GROrderedMultiMap,
#superclass : #GRSmallDictionary,
#category : #'Grease-Core-Collections'
}
{ #category : #accessing }
GROrderedMultiMap >> add: anAssociation [
self privateAt: anAssociation key put: anAssociation value.
^ anAssociation
]
{ #category : #adding }
GROrderedMultiMap >> addAll: aDictionary [
aDictionary keysAndValuesDo: [ :key :value |
self privateAt: key put: value ].
^ aDictionary
]
{ #category : #accessing }
GROrderedMultiMap >> allAt: aKey [
^ Array streamContents: [ :stream |
1 to: size do: [ :index |
(keys at: index) = aKey
ifTrue: [ stream nextPut: (values at: index) ] ] ]
]
{ #category : #accessing }
GROrderedMultiMap >> allAt: aKey ifAbsent: absentBlock [
| results |
results := self allAt: aKey.
^ results isEmpty
ifTrue: [ absentBlock value ]
ifFalse: [ results ]
]
{ #category : #accessing }
GROrderedMultiMap >> at: aKey add: aValue [
"Add an association between aKey and aValue. Do not replace existing
values with the same key."
^ self privateAt: aKey put: aValue
]
{ #category : #enumerating }
GROrderedMultiMap >> keysAndAllValuesDo: aTwoArgumentBlock [
| seenKeys |
seenKeys := GRSmallOrderedSet new.
1 to: size do: [ :index |
| key |
key := keys at: index.
(seenKeys includes: key) ifFalse: [
aTwoArgumentBlock
value: key
value: (self privateAllAt: key startingAt: index).
seenKeys add: key ] ]
]
{ #category : #private }
GROrderedMultiMap >> privateAllAt: aKey startingAt: aStartInteger [
^ Array new: 2 streamContents: [ :stream |
aStartInteger to: size do: [ :index |
(keys at: index) = aKey
ifTrue: [ stream nextPut: (values at: index) ] ] ]
]
{ #category : #accessing }
GROrderedMultiMap >> removeKey: aKey ifAbsent: aBlock [
"Remove aKey from the receiver, evaluate aBlock if the element is missing."
"This is inefficient and could be optimized."
| removed |
removed := Array new: 2 streamContents: [ :stream |
| index |
[ (index := self findIndexFor: aKey) = 0 ] whileFalse: [
stream nextPut: (self removeIndex: index) ] ].
^ removed isEmpty
ifTrue: [ aBlock value ]
ifFalse: [ removed ]
]