121 in |
121 in |
122 fun index (i, sz) = andb_ i (sz-1) |
122 fun index (i, sz) = andb_ i (sz-1) |
123 |
123 |
124 (* find smallest power of 2 (>= 32) that is >= n *) |
124 (* find smallest power of 2 (>= 32) that is >= n *) |
125 fun roundUp n = |
125 fun roundUp n = |
126 let fun f i = if (i >= n) then i else f (lshift_ i 1) |
126 let fun f i = if (i >= n) then i else f (lshift_ i 1) |
127 in f 32 end |
127 in f 32 end |
128 end; |
128 end; |
129 |
129 |
130 (* Create a new table; the int is a size hint and the exception |
130 (* Create a new table; the int is a size hint and the exception |
131 * is to be raised by find. |
131 * is to be raised by find. |
132 *) |
132 *) |
133 fun mkTable (hashVal, sameKey) (sizeHint, notFound) = HT{ |
133 fun mkTable (hashVal, sameKey) (sizeHint, notFound) = HT{ |
134 hashVal=hashVal, |
134 hashVal=hashVal, |
135 sameKey=sameKey, |
135 sameKey=sameKey, |
136 not_found = notFound, |
136 not_found = notFound, |
137 table = Unsynchronized.ref (Array.array(roundUp sizeHint, NIL)), |
137 table = Unsynchronized.ref (Array.array(roundUp sizeHint, NIL)), |
138 n_items = Unsynchronized.ref 0 |
138 n_items = Unsynchronized.ref 0 |
139 }; |
139 }; |
140 |
140 |
141 (* conditionally grow a table *) |
141 (* conditionally grow a table *) |
142 fun growTable (HT{table, n_items, ...}) = let |
142 fun growTable (HT{table, n_items, ...}) = let |
143 val arr = !table |
143 val arr = !table |
144 val sz = Array.length arr |
144 val sz = Array.length arr |
145 in |
145 in |
146 if (!n_items >= sz) |
146 if (!n_items >= sz) |
147 then let |
147 then let |
148 val newSz = sz+sz |
148 val newSz = sz+sz |
149 val newArr = Array.array (newSz, NIL) |
149 val newArr = Array.array (newSz, NIL) |
150 fun copy NIL = () |
150 fun copy NIL = () |
151 | copy (B(h, key, v, rest)) = let |
151 | copy (B(h, key, v, rest)) = let |
152 val indx = index (h, newSz) |
152 val indx = index (h, newSz) |
153 in |
153 in |
154 Array.update (newArr, indx, |
154 Array.update (newArr, indx, |
155 B(h, key, v, Array.sub(newArr, indx))); |
155 B(h, key, v, Array.sub(newArr, indx))); |
156 copy rest |
156 copy rest |
157 end |
157 end |
158 fun bucket n = (copy (Array.sub(arr, n)); bucket (n+1)) |
158 fun bucket n = (copy (Array.sub(arr, n)); bucket (n+1)) |
159 in |
159 in |
160 (bucket 0) handle _ => (); (* FIXME avoid handle _ *) |
160 (bucket 0) handle _ => (); (* FIXME avoid handle _ *) |
161 table := newArr |
161 table := newArr |
162 end |
162 end |
163 else () |
163 else () |
164 end (* growTable *); |
164 end (* growTable *); |
165 |
165 |
166 (* Insert an item. If the key already has an item associated with it, |
166 (* Insert an item. If the key already has an item associated with it, |
167 * then the old item is discarded. |
167 * then the old item is discarded. |
168 *) |
168 *) |
169 fun insert (tbl as HT{hashVal, sameKey, table, n_items, ...}) (key, item) = |
169 fun insert (tbl as HT{hashVal, sameKey, table, n_items, ...}) (key, item) = |
170 let |
170 let |
171 val arr = !table |
171 val arr = !table |
172 val sz = Array.length arr |
172 val sz = Array.length arr |
173 val hash = hashVal key |
173 val hash = hashVal key |
174 val indx = index (hash, sz) |
174 val indx = index (hash, sz) |
175 fun look NIL = ( |
175 fun look NIL = ( |
176 Array.update(arr, indx, B(hash, key, item, Array.sub(arr, indx))); |
176 Array.update(arr, indx, B(hash, key, item, Array.sub(arr, indx))); |
177 Unsynchronized.inc n_items; |
177 Unsynchronized.inc n_items; |
178 growTable tbl; |
178 growTable tbl; |
179 NIL) |
179 NIL) |
180 | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k)) |
180 | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k)) |
181 then B(hash, key, item, r) |
181 then B(hash, key, item, r) |
182 else (case (look r) |
182 else (case (look r) |
183 of NIL => NIL |
183 of NIL => NIL |
184 | rest => B(h, k, v, rest) |
184 | rest => B(h, k, v, rest) |
185 (* end case *)) |
185 (* end case *)) |
186 in |
186 in |
187 case (look (Array.sub (arr, indx))) |
187 case (look (Array.sub (arr, indx))) |
188 of NIL => () |
188 of NIL => () |
189 | b => Array.update(arr, indx, b) |
189 | b => Array.update(arr, indx, b) |
190 end; |
190 end; |
191 |
191 |
192 (* Insert an item if not there already; if it is there already, |
192 (* Insert an item if not there already; if it is there already, |
193 then return the old data value and leave the table unmodified.. |
193 then return the old data value and leave the table unmodified.. |
194 *) |
194 *) |
195 fun peekInsert (tbl as HT{hashVal, sameKey, table, n_items, ...}) (key, item) = |
195 fun peekInsert (tbl as HT{hashVal, sameKey, table, n_items, ...}) (key, item) = |
196 let val arr = !table |
196 let val arr = !table |
197 val sz = Array.length arr |
197 val sz = Array.length arr |
198 val hash = hashVal key |
198 val hash = hashVal key |
199 val indx = index (hash, sz) |
199 val indx = index (hash, sz) |
200 fun look NIL = |
200 fun look NIL = |
201 (Array.update(arr, indx, B(hash, key, item, |
201 (Array.update(arr, indx, B(hash, key, item, |
202 Array.sub(arr, indx))); |
202 Array.sub(arr, indx))); |
203 Unsynchronized.inc n_items; |
203 Unsynchronized.inc n_items; |
204 growTable tbl; |
204 growTable tbl; |
205 NONE) |
205 NONE) |
206 | look (B(h, k, v, r)) = |
206 | look (B(h, k, v, r)) = |
207 if hash = h andalso sameKey(key, k) then SOME v |
207 if hash = h andalso sameKey(key, k) then SOME v |
208 else look r |
208 else look r |
209 in |
209 in |
210 look (Array.sub (arr, indx)) |
210 look (Array.sub (arr, indx)) |
211 end; |
211 end; |
212 |
212 |
213 (* find an item, the table's exception is raised if the item doesn't exist *) |
213 (* find an item, the table's exception is raised if the item doesn't exist *) |
214 fun find (HT{hashVal, sameKey, table, not_found, ...}) key = let |
214 fun find (HT{hashVal, sameKey, table, not_found, ...}) key = let |
215 val arr = !table |
215 val arr = !table |
216 val sz = Array.length arr |
216 val sz = Array.length arr |
217 val hash = hashVal key |
217 val hash = hashVal key |
218 val indx = index (hash, sz) |
218 val indx = index (hash, sz) |
219 fun look NIL = raise not_found |
219 fun look NIL = raise not_found |
220 | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k)) |
220 | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k)) |
221 then v |
221 then v |
222 else look r |
222 else look r |
223 in |
223 in |
224 look (Array.sub (arr, indx)) |
224 look (Array.sub (arr, indx)) |
225 end; |
225 end; |
226 |
226 |
227 (* look for an item, return NONE if the item doesn't exist *) |
227 (* look for an item, return NONE if the item doesn't exist *) |
228 fun peek (HT{hashVal, sameKey, table, ...}) key = let |
228 fun peek (HT{hashVal, sameKey, table, ...}) key = let |
229 val arr = !table |
229 val arr = !table |
230 val sz = Array.length arr |
230 val sz = Array.length arr |
231 val hash = hashVal key |
231 val hash = hashVal key |
232 val indx = index (hash, sz) |
232 val indx = index (hash, sz) |
233 fun look NIL = NONE |
233 fun look NIL = NONE |
234 | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k)) |
234 | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k)) |
235 then SOME v |
235 then SOME v |
236 else look r |
236 else look r |
237 in |
237 in |
238 look (Array.sub (arr, indx)) |
238 look (Array.sub (arr, indx)) |
239 end; |
239 end; |
240 |
240 |
241 (* Remove an item. The table's exception is raised if |
241 (* Remove an item. The table's exception is raised if |
242 * the item doesn't exist. |
242 * the item doesn't exist. |
243 *) |
243 *) |
244 fun remove (HT{hashVal, sameKey, not_found, table, n_items}) key = let |
244 fun remove (HT{hashVal, sameKey, not_found, table, n_items}) key = let |
245 val arr = !table |
245 val arr = !table |
246 val sz = Array.length arr |
246 val sz = Array.length arr |
247 val hash = hashVal key |
247 val hash = hashVal key |
248 val indx = index (hash, sz) |
248 val indx = index (hash, sz) |
249 fun look NIL = raise not_found |
249 fun look NIL = raise not_found |
250 | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k)) |
250 | look (B(h, k, v, r)) = if ((hash = h) andalso sameKey(key, k)) |
251 then (v, r) |
251 then (v, r) |
252 else let val (item, r') = look r in (item, B(h, k, v, r')) end |
252 else let val (item, r') = look r in (item, B(h, k, v, r')) end |
253 val (item, bucket) = look (Array.sub (arr, indx)) |
253 val (item, bucket) = look (Array.sub (arr, indx)) |
254 in |
254 in |
255 Array.update (arr, indx, bucket); |
255 Array.update (arr, indx, bucket); |
256 n_items := !n_items - 1; |
256 n_items := !n_items - 1; |
257 item |
257 item |
258 end (* remove *); |
258 end (* remove *); |
259 |
259 |
260 (* Return the number of items in the table *) |
260 (* Return the number of items in the table *) |
261 fun numItems (HT{n_items, ...}) = !n_items |
261 fun numItems (HT{n_items, ...}) = !n_items |
262 |
262 |
263 (* return a list of the items in the table *) |
263 (* return a list of the items in the table *) |
264 fun listItems (HT{table = Unsynchronized.ref arr, n_items, ...}) = let |
264 fun listItems (HT{table = Unsynchronized.ref arr, n_items, ...}) = let |
265 fun f (_, l, 0) = l |
265 fun f (_, l, 0) = l |
266 | f (~1, l, _) = l |
266 | f (~1, l, _) = l |
267 | f (i, l, n) = let |
267 | f (i, l, n) = let |
268 fun g (NIL, l, n) = f (i-1, l, n) |
268 fun g (NIL, l, n) = f (i-1, l, n) |
269 | g (B(_, k, v, r), l, n) = g(r, (k, v)::l, n-1) |
269 | g (B(_, k, v, r), l, n) = g(r, (k, v)::l, n-1) |
270 in |
270 in |
271 g (Array.sub(arr, i), l, n) |
271 g (Array.sub(arr, i), l, n) |
272 end |
272 end |
273 in |
273 in |
274 f ((Array.length arr) - 1, [], !n_items) |
274 f ((Array.length arr) - 1, [], !n_items) |
275 end (* listItems *); |
275 end (* listItems *); |
276 |
276 |
277 (* Apply a function to the entries of the table *) |
277 (* Apply a function to the entries of the table *) |
278 fun apply f (HT{table, ...}) = let |
278 fun apply f (HT{table, ...}) = let |
279 fun appF NIL = () |
279 fun appF NIL = () |
280 | appF (B(_, key, item, rest)) = ( |
280 | appF (B(_, key, item, rest)) = ( |
281 f (key, item); |
281 f (key, item); |
282 appF rest) |
282 appF rest) |
283 val arr = !table |
283 val arr = !table |
284 val sz = Array.length arr |
284 val sz = Array.length arr |
285 fun appToTbl i = if (i < sz) |
285 fun appToTbl i = if (i < sz) |
286 then (appF (Array.sub (arr, i)); appToTbl(i+1)) |
286 then (appF (Array.sub (arr, i)); appToTbl(i+1)) |
287 else () |
287 else () |
288 in |
288 in |
289 appToTbl 0 |
289 appToTbl 0 |
290 end (* apply *); |
290 end (* apply *); |
291 |
291 |
292 (* Map a table to a new table that has the same keys and exception *) |
292 (* Map a table to a new table that has the same keys and exception *) |
293 fun map f (HT{hashVal, sameKey, table, n_items, not_found}) = let |
293 fun map f (HT{hashVal, sameKey, table, n_items, not_found}) = let |
294 fun mapF NIL = NIL |
294 fun mapF NIL = NIL |
295 | mapF (B(hash, key, item, rest)) = |
295 | mapF (B(hash, key, item, rest)) = |
296 B(hash, key, f (key, item), mapF rest) |
296 B(hash, key, f (key, item), mapF rest) |
297 val arr = !table |
297 val arr = !table |
298 val sz = Array.length arr |
298 val sz = Array.length arr |
299 val newArr = Array.array (sz, NIL) |
299 val newArr = Array.array (sz, NIL) |
300 fun mapTbl i = if (i < sz) |
300 fun mapTbl i = if (i < sz) |
301 then ( |
301 then ( |
302 Array.update(newArr, i, mapF (Array.sub(arr, i))); |
302 Array.update(newArr, i, mapF (Array.sub(arr, i))); |
303 mapTbl (i+1)) |
303 mapTbl (i+1)) |
304 else () |
304 else () |
305 in |
305 in |
306 mapTbl 0; |
306 mapTbl 0; |
307 HT{hashVal=hashVal, |
307 HT{hashVal=hashVal, |
308 sameKey=sameKey, |
308 sameKey=sameKey, |
309 table = Unsynchronized.ref newArr, |
309 table = Unsynchronized.ref newArr, |
310 n_items = Unsynchronized.ref(!n_items), |
310 n_items = Unsynchronized.ref(!n_items), |
311 not_found = not_found} |
311 not_found = not_found} |
312 end (* transform *); |
312 end (* transform *); |
313 |
313 |
314 (* remove any hash table items that do not satisfy the given |
314 (* remove any hash table items that do not satisfy the given |
315 * predicate. |
315 * predicate. |
316 *) |
316 *) |
317 fun filter pred (HT{table, n_items, not_found, ...}) = let |
317 fun filter pred (HT{table, n_items, not_found, ...}) = let |
318 fun filterP NIL = NIL |
318 fun filterP NIL = NIL |
319 | filterP (B(hash, key, item, rest)) = if (pred(key, item)) |
319 | filterP (B(hash, key, item, rest)) = if (pred(key, item)) |
320 then B(hash, key, item, filterP rest) |
320 then B(hash, key, item, filterP rest) |
321 else filterP rest |
321 else filterP rest |
322 val arr = !table |
322 val arr = !table |
323 val sz = Array.length arr |
323 val sz = Array.length arr |
324 fun filterTbl i = if (i < sz) |
324 fun filterTbl i = if (i < sz) |
325 then ( |
325 then ( |
326 Array.update (arr, i, filterP (Array.sub (arr, i))); |
326 Array.update (arr, i, filterP (Array.sub (arr, i))); |
327 filterTbl (i+1)) |
327 filterTbl (i+1)) |
328 else () |
328 else () |
329 in |
329 in |
330 filterTbl 0 |
330 filterTbl 0 |
331 end (* filter *); |
331 end (* filter *); |
332 |
332 |
333 (* Map a table to a new table that has the same keys, exception, |
333 (* Map a table to a new table that has the same keys, exception, |
334 hash function, and equality function *) |
334 hash function, and equality function *) |
335 |
335 |
336 fun transform f (HT{hashVal, sameKey, table, n_items, not_found}) = let |
336 fun transform f (HT{hashVal, sameKey, table, n_items, not_found}) = let |
337 fun mapF NIL = NIL |
337 fun mapF NIL = NIL |
338 | mapF (B(hash, key, item, rest)) = B(hash, key, f item, mapF rest) |
338 | mapF (B(hash, key, item, rest)) = B(hash, key, f item, mapF rest) |
339 val arr = !table |
339 val arr = !table |
340 val sz = Array.length arr |
340 val sz = Array.length arr |
341 val newArr = Array.array (sz, NIL) |
341 val newArr = Array.array (sz, NIL) |
342 fun mapTbl i = if (i < sz) |
342 fun mapTbl i = if (i < sz) |
343 then ( |
343 then ( |
344 Array.update(newArr, i, mapF (Array.sub(arr, i))); |
344 Array.update(newArr, i, mapF (Array.sub(arr, i))); |
345 mapTbl (i+1)) |
345 mapTbl (i+1)) |
346 else () |
346 else () |
347 in |
347 in |
348 mapTbl 0; |
348 mapTbl 0; |
349 HT{hashVal=hashVal, |
349 HT{hashVal=hashVal, |
350 sameKey=sameKey, |
350 sameKey=sameKey, |
351 table = Unsynchronized.ref newArr, |
351 table = Unsynchronized.ref newArr, |
352 n_items = Unsynchronized.ref(!n_items), |
352 n_items = Unsynchronized.ref(!n_items), |
353 not_found = not_found} |
353 not_found = not_found} |
354 end (* transform *); |
354 end (* transform *); |
355 |
355 |
356 (* Create a copy of a hash table *) |
356 (* Create a copy of a hash table *) |
357 fun copy (HT{hashVal, sameKey, table, n_items, not_found}) = let |
357 fun copy (HT{hashVal, sameKey, table, n_items, not_found}) = let |
358 val arr = !table |
358 val arr = !table |
359 val sz = Array.length arr |
359 val sz = Array.length arr |
360 val newArr = Array.array (sz, NIL) |
360 val newArr = Array.array (sz, NIL) |
361 fun mapTbl i = ( |
361 fun mapTbl i = ( |
362 Array.update (newArr, i, Array.sub(arr, i)); |
362 Array.update (newArr, i, Array.sub(arr, i)); |
363 mapTbl (i+1)) |
363 mapTbl (i+1)) |
364 in |
364 in |
365 (mapTbl 0) handle _ => (); (* FIXME avoid handle _ *) |
365 (mapTbl 0) handle _ => (); (* FIXME avoid handle _ *) |
366 HT{hashVal=hashVal, |
366 HT{hashVal=hashVal, |
367 sameKey=sameKey, |
367 sameKey=sameKey, |
368 table = Unsynchronized.ref newArr, |
368 table = Unsynchronized.ref newArr, |
369 n_items = Unsynchronized.ref(!n_items), |
369 n_items = Unsynchronized.ref(!n_items), |
370 not_found = not_found} |
370 not_found = not_found} |
371 end (* copy *); |
371 end (* copy *); |
372 |
372 |
373 (* returns a list of the sizes of the various buckets. This is to |
373 (* returns a list of the sizes of the various buckets. This is to |
374 * allow users to gauge the quality of their hashing function. |
374 * allow users to gauge the quality of their hashing function. |
375 *) |
375 *) |
376 fun bucketSizes (HT{table = Unsynchronized.ref arr, ...}) = let |
376 fun bucketSizes (HT{table = Unsynchronized.ref arr, ...}) = let |
377 fun len (NIL, n) = n |
377 fun len (NIL, n) = n |
378 | len (B(_, _, _, r), n) = len(r, n+1) |
378 | len (B(_, _, _, r), n) = len(r, n+1) |
379 fun f (~1, l) = l |
379 fun f (~1, l) = l |
380 | f (i, l) = f (i-1, len (Array.sub (arr, i), 0) :: l) |
380 | f (i, l) = f (i-1, len (Array.sub (arr, i), 0) :: l) |
381 in |
381 in |
382 f ((Array.length arr)-1, []) |
382 f ((Array.length arr)-1, []) |
383 end |
383 end |
384 |
384 |
385 (*Added by lcp. |
385 (*Added by lcp. |
386 This is essentially the described in Compilers: |
386 This is essentially the described in Compilers: |
387 Principles, Techniques, and Tools, by Aho, Sethi and Ullman.*) |
387 Principles, Techniques, and Tools, by Aho, Sethi and Ullman.*) |
388 |
388 |