1 collections define: #Dictionary &parents: {Set. Mapping} &slots: {#values -> (Array newSize: 10)}.
5 Dictionary identityHash.
7 "Dictionary uses two separate arrays to store its keys and values; it behaves
8 as a Set of key-value pairs (but doesn't store Associations as in Smalltalk)."
9 "Stores the associated values for the array's objects which are the keys.
10 The correspondence is per-index, and there can obviously be only one value
13 d@(Dictionary traits) copy
14 [resend `>> [values := d values copy. ]].
16 d@(Dictionary traits) new &capacity: n
20 values := d values new &capacity: ((n ifNil: [0]) max: newD contents size). ]
23 d@(Dictionary traits) newFrom: keys@(Sequence traits) to: values@(Sequence traits)
25 result ::= d new &capacity: (keys size min: values size).
26 keys with: values do: #(result at: _ put: _) `er.
30 collections IdentityDictionary ::= Dictionary copy `>>
31 [hashBlock := #identityHash`er.
32 equalsBlock := #==`er. ].
33 "IdentityDictionary is an alternate prototype Dictionary using ==-based
34 comparison and hashing."
36 d@(Dictionary traits) acceptsKey: _@Nil
39 d@(Dictionary traits) = e@(Dictionary traits)
43 /\ [d keysAndValuesDo:
45 (e at: key ifAbsent: [^ False]) = value ifFalse: [^ False]].
49 d@(Dictionary traits) clear
56 d@(Dictionary traits) includes: obj
57 "Returns whether the Dictionary includes the object as a value."
59 (d detect: [| :each | d equalsBlock apply*, obj, each]) isNotNil
62 d@(Dictionary traits) includesIdentity: obj
63 "Returns whether the object is identical to some keyed value."
65 (d detect: [| :each | obj == each]) isNotNil
68 d@(Dictionary traits) occurrencesOf: obj
69 "The number of indexed values equal to obj."
72 d do: [| :each | (d equalsBlock apply*, obj, each)
73 ifTrue: [count += 1]].
77 d@(Dictionary traits) addAll: map@(Mapping traits)
78 "Adds all of the key-value pairs to the Dictionary. Notice that this works
79 for any Mapping, but that other collections will not do."
82 [map keysAndValuesDo: #(d at: _ put: _) `er].
86 d@(Dictionary traits) addAll: seq@(Sequence traits)
88 seq doWithIndex: [| :assoc :index |
89 (assoc isSameAs: Association)
90 ifTrue: [d add: assoc]
91 ifFalse: [d at: index put: assoc]].
95 d@(Dictionary traits) declare: key from: e@(Dictionary traits)
96 "Add key to d, unless the key already exists. Remove key from e
97 and move its association to d."
99 (d includesKey: key) ifFalse:
100 [(e includesKey: key)
101 ifTrue: [d add: (e associationAt: key).
103 ifFalse: [d add: key -> Nil]].
107 d@(Dictionary traits) associationAt: key ifAbsent: block
109 (d contents at: (index ::= d scanFor: key))
111 ifNotNil: [(d contents at: index) -> (d values at: index)]
114 d@(Dictionary traits) associationAt: key
116 d associationAt: key ifAbsent: [key keyNotFoundOn: d]
119 d@(Dictionary traits) at: key ifAbsent: block
121 (d contents at: (index ::= d scanFor: key))
123 ifNotNil: [d values at: index]
126 d@(Dictionary traits) add: assoc@(Association traits)
127 "Adds a new key value pair to the Dictionary from an assocation.
128 For example: Dictionary new `>> [ add: 'first' -> 'Joe Henry'. ]."
130 d at: assoc key put: assoc value.
134 d@(Dictionary traits) at: key put: obj
136 (d contents at: (index ::= d scanFor: key)) ifNil:
137 [d contents at: index put: key.
139 d values at: index put: obj.
144 d@(Dictionary traits) acceptsKey: _@Nil [False].
145 d@(Dictionary traits) at: _@Nil put: obj
146 [error: 'Dictionary cannot accept Nil keys.'].
147 "TODO: extend Dictionary to handle Nil keys."
149 d@(Dictionary traits) keyAtValue: obj ifAbsent: block
151 d keysAndValuesDo: [| :key :value |
152 (d equalsBlock apply*, obj, value) ifTrue: [^ key]].
156 d@(Dictionary traits) keyAtIdentityValue: obj ifAbsent: block
158 d values doWithIndex: [| :each :index | each == obj
159 ifTrue: [^ (d contents at: index)]].
163 d@(Dictionary traits) keyAtIdentityValue: obj
165 d keyAtIdentityValue: obj ifAbsent: [obj elementNotFoundOn: d]
168 d@(Dictionary traits) keySet
170 result ::= Set newSizeOf: d.
171 result equalsBlock := d equalsBlock.
172 d keysDo: #(result add: _) `er.
176 d@(Dictionary traits) keys [d keySet].
178 d@(Dictionary traits) valueSet
180 result ::= Set newSizeOf: d.
181 result equalsBlock := d equalsBlock.
182 d valuesDo: #(result add: _) `er.
186 d@(Dictionary traits) values [d valueSet].
188 d@(Dictionary traits) keysAndValuesDo: block
191 [d contents doWithIndex:
193 each ifNotNil: [block apply*, each, (d values at: index)]]]
196 d@(Dictionary traits) keysDo: block
199 [d contents doWithIndex:
200 [| :each :index | each ifNotNil: [block apply*, each]]]
203 d@(Dictionary traits) valuesDo: block
206 [d contents doWithIndex:
207 [| :each :index | each ifNotNil: [block apply*, (d values at: index)]]]
210 d@(Dictionary traits) keysAndValuesRemove: block
211 "Removes key-value pairs that satisfy the two-argument block."
213 removals ::= ExtensibleArray new.
214 d keysAndValuesDo: [| :key :value | (block apply*, key, value)
215 ifTrue: [removals add: key]].
216 removals do: #(d removeKey: _) `er.
220 d@(Dictionary traits) removeKey: key ifAbsent: block
222 (index ::= d scanFor: key)
224 value ::= d contents at: index.
225 d contents at: index put: Nil.
226 d values at: index put: Nil.
228 d fixCollisionsFrom: index.
232 d@(Dictionary traits) removeKey: key
234 d removeKey: key ifAbsent: [key keyNotFoundOn: d]
237 d@(Dictionary traits) remove: key
242 d@(Dictionary traits) remove: key ifAbsent: block
244 d removeKey: key ifAbsent: block
247 d@(Dictionary traits) associationsDo: block
250 [d contents doWithIndex:
251 [| :each :index | each ifNotNil:
252 [block apply*, (each -> (d values at: index))]]]
255 d@(Dictionary traits) do: block
256 "Applies a single-argument block to each keyed value in the Dictionary.
257 Equivalent to valuesDo:."
260 d mapSelect: block into: result@(Dictionary traits)
261 "Filter the dictionary by values satisfying a block."
263 [| :key :value | (block apply*, key, value)
264 ifTrue: [result noCheckAt: key put: value]].
268 d select: block into: result@(Dictionary traits)
269 [d mapSelect: [| :_ :value | block apply*, each] into: result].
271 d@(Dictionary traits) collect: block
272 "Generate a new collection based on applying the block to each value."
274 result ::= ExtensibleArray new.
275 d do: [| :each | result add: (block apply*, each)].
279 d@(Dictionary traits) swap: index1 with: index2
281 d contents swap: index1 with: index2.
282 d values swap: index1 with: index2.
286 d@(Dictionary traits) noCheckAt: key put: value
288 index ::= d scanFor: key.
289 d contents at: index put: key.
290 d values at: index put: value.
294 d@(Dictionary traits) noCheckAdd: assoc
296 d noCheckAt: assoc key put: assoc value
299 d@(Dictionary traits) growBy: growthAmount
301 tempDict ::= d new &capacity: d contents size + growthAmount.
302 d keysAndValuesDo: #(tempDict noCheckAt: _ put: _) `er.
303 d contents := tempDict contents.
304 d values := tempDict values.
308 d@(Dictionary traits) rehash
310 tempDict ::= d newSameSize.
311 d keysAndValuesDo: #(tempDict noCheckAt: _ put: _) `er.
312 d contents := tempDict contents.
313 d values := tempDict values.
317 d@(Dictionary traits) scanFor: obj
318 "Scans the key array for the first empty slot or an element matching the
319 object. Returns the index at which the object is used as a key, or Nil if
320 it's not found and the Dictionary is full."
322 end ::= d contents size.
323 start ::= ((d hashBlock apply*, obj) \\ end) + 1.
326 (key := d contents at: index) isNil \/
327 [d equalsBlock apply*, obj, key]
329 start below: end do: block.
330 0 below: start do: block.
334 x@(Root traits) slotNamesAndValues
335 "Answers a Dictionary of the slot names and values from the argument."
337 result ::= Dictionary new.
338 x slotNamesAndValuesDo: #(result at: _ put: _) `er.