Core code source usage of ::= and other cleanups.
[cslatevm.git] / src / core / dictionary.slate
blob5fb07313da300f6a8084ebad71b1913eab333946
1 collections define: #Dictionary &parents: {Set. Mapping} &slots: {#values -> (Array newSize: 10)}.
3 Set identityHash.
4 Mapping identityHash.
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
11 per key."
13 d@(Dictionary traits) copy
14 [resend `>> [values := d values copy. ]].
16 d@(Dictionary traits) new &capacity: n
18   resend `>>
19     [| :newD |
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.
27   result
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
37 [False].
39 d@(Dictionary traits) = e@(Dictionary traits)
41   d == e
42    \/ [d size = e size
43          /\ [d keysAndValuesDo:
44                [| :key :value |
45                 (e at: key ifAbsent: [^ False]) = value ifFalse: [^ False]].
46              True]]
49 d@(Dictionary traits) clear
51   resend.
52   d values clear.
53   d
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."
70 [| count |
71   count := 0.
72   d do: [| :each | (d equalsBlock apply*, obj, each)
73     ifTrue: [count += 1]].
74   count
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."
81   d == map ifFalse:
82     [map keysAndValuesDo: #(d at: _ put: _) `er].
83   map
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]].
92   seq
94       
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).
102                 e removeKey: key]
103        ifFalse: [d add: key -> Nil]].
104   d
107 d@(Dictionary traits) associationAt: key ifAbsent: block
109   (d contents at: (index ::= d scanFor: key))
110     ifNil: [block do]
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))
122     ifNil: [block do]
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.
131   assoc
134 d@(Dictionary traits) at: key put: obj
136   (d contents at: (index ::= d scanFor: key)) ifNil:
137     [d contents at: index put: key.
138      d tally += 1].
139   d values at: index put: obj.
140   d fullCheck.
141   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]].
153   block do
156 d@(Dictionary traits) keyAtIdentityValue: obj ifAbsent: block
158   d values doWithIndex: [| :each :index | each == obj
159     ifTrue: [^ (d contents at: index)]].
160   block do
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.
173   result
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.
183   result
186 d@(Dictionary traits) values [d valueSet].
188 d@(Dictionary traits) keysAndValuesDo: block
190   d isEmpty ifFalse:
191     [d contents doWithIndex:
192        [| :each :index |
193         each ifNotNil: [block apply*, each, (d values at: index)]]]
196 d@(Dictionary traits) keysDo: block
198   d isEmpty ifFalse:
199     [d contents doWithIndex:
200        [| :each :index | each ifNotNil: [block apply*, each]]]
203 d@(Dictionary traits) valuesDo: block
205   d isEmpty ifFalse:
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.
217   d
220 d@(Dictionary traits) removeKey: key ifAbsent: block
222   (index ::= d scanFor: key)
223     ifNil: [^ block do].
224   value ::= d contents at: index.
225   d contents at: index put: Nil.
226   d values at: index put: Nil.
227   d tally -= 1.
228   d fixCollisionsFrom: index.
229   value
232 d@(Dictionary traits) removeKey: key
234   d removeKey: key ifAbsent: [key keyNotFoundOn: d]
237 d@(Dictionary traits) remove: key
239   d removeKey: key
242 d@(Dictionary traits) remove: key ifAbsent: block
244   d removeKey: key ifAbsent: block
247 d@(Dictionary traits) associationsDo: block
249   d isEmpty ifFalse:
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:."
258 [d valuesDo: block].
260 d mapSelect: block into: result@(Dictionary traits)
261 "Filter the dictionary by values satisfying a block."
262 [d keysAndValuesDo:
263   [| :key :value | (block apply*, key, value)
264       ifTrue: [result noCheckAt: key put: value]].
265   result
268 d select: block into: result@(Dictionary traits)
269 [d mapSelect: [| :_ :value | block apply*, each] into: result].
270   
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)].
276   result
279 d@(Dictionary traits) swap: index1 with: index2
281   d contents swap: index1 with: index2.
282   d values swap: index1 with: index2.
283   d
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.
291   d tally += 1.
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.
305   d
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.
314   d
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."
321 [| key |
322   end ::= d contents size.
323   start ::= ((d hashBlock apply*, obj) \\ end) + 1.
324   block ::=
325     [| :index |
326      (key := d contents at: index) isNil \/
327        [d equalsBlock apply*, obj, key]
328        ifTrue: [^ index]].
329   start below: end do: block.
330   0 below: start do: block.
331   Nil
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.
339   result