1 open bucket
  2 
  3 
  4 
  5 
  6 
  7 
  8 mutable data table k a =
  9   Table {
 10     
 11     cardinal: int;
 12     
 13     buckets: array (bucket k a);
 14     
 15     hash: k -> int;
 16     
 17     equal: (k, k) -> bool
 18   }
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 val create_buckets [k, a] (capacity: int) : array (bucket k a) =
 28   array::init (Up, array::above (16, capacity), fun (i: int) : bucket k a = BNil)
 29 
 30 
 31 
 32 val create [k, a] (capacity: int, hash: k -> int, equal: (k, k) -> bool) : table k a =
 33   Table {
 34     cardinal = 0;
 35     buckets = create_buckets capacity;
 36     hash = hash;
 37     equal = equal
 38   }
 39 
 40 
 41 
 42 
 43 
 44 
 45 
 46 
 47 
 48 
 49 
 50 
 51 
 52 
 53 
 54 
 55 
 56 
 57 
 58 val key_index [k, a, buckets : term] (
 59   t: Table { cardinal: int; buckets = buckets; hash: k -> int; equal: (k, k) -> bool },
 60   x: k
 61   | buckets @ array (bucket k a)
 62 ) : int =
 63   t.hash x & (array::length t.buckets - 1)
 64 
 65 
 66 
 67 
 68 val push [k, a] (
 69   t: table k a,
 70   consumes entry: BCons { key: k; value: a; tail: unknown }
 71 ) : () =
 72   let i = key_index (t, entry.key) in
 73   array::update (t.buckets, i,
 74     fun (consumes b: bucket k a | consumes entry @ BCons { key: k; value: a; tail: unknown }) : bucket k a =
 75       entry.tail <- b;
 76       entry
 77   )
 78 
 79 
 80 
 81 
 82 
 83 
 84 
 85 val push_bucket [k, a]
 86   (t: unknown) :
 87   (int, consumes bucket k a | t @ table k a) -> () =
 88   fun (_: int, consumes b: bucket k a | t @ table k a) : () =
 89     iter_bucket_down (b, fun (consumes entry: BCons { key: k; value: a; tail: unknown } | t @ table k a) : () =
 90       push (t, entry)
 91     )
 92 
 93 
 94 
 95 
 96 val resize [k, a] (t: table k a) : () =
 97   let old_buckets = t.buckets in
 98   let new_size = array::length old_buckets * 2 in
 99   if new_size < array::max_length then begin
100     
101 
102     t.buckets <- array::init (Up, new_size, fun (i: int) : bucket k a = BNil);
103     
104 
105 
106     array::transform (Up, old_buckets, push_bucket t)
107   end
108 
109 
110 
111 
112 
113 val merge [k, a] (consumes t1: table k a, t2: table k a) : () =
114   
115   t2.cardinal <- t2.cardinal + t1.cardinal;
116   
117 
118   array::transform (Up, t1.buckets, push_bucket t2);
119   
120 
121 
122   let rec loop (| t2 @ table k a) : () =
123     if t2.cardinal > 2 * array::length t2.buckets then begin
124       resize t2;
125       loop()
126     end
127   in
128   loop()
129 
130 
131 
132 
133 
134 
135 
136 val clear [k, a] (t: table k a) : () =
137   t.cardinal <- 0;
138   array::transform (Up, t.buckets, fun (i: int, _: bucket k a) : bucket k a = BNil)
139 
140 val reset [k, a] (t: table k a, capacity: int) : () =
141   t.cardinal <- 0;
142   t.buckets <- create_buckets capacity
143 
144 
145 
146 
147 
148 val add [k, a] (consumes x: k, consumes v: a, t: table k a) : () =
149   push (t, BCons { key = x; value = v; tail = () });
150   t.cardinal <- t.cardinal + 1;
151   if t.cardinal > 2 * array::length t.buckets then
152     resize t
153 
154 
155 
156 
157 
158 
159 
160 
161 
162 
163 
164 
165 
166 val remove [k, a] (x: k, t: table k a) : option a =
167 
168   let equal = t.equal in
169 
170   
171   let ok (key: k | x @ k) : bool =
172     equal (key, x)
173   in
174 
175   
176   let r = newref none in
177 
178   
179 
180 
181   let remove (consumes b: bucket k a | x @ k * r @ ref (option a)) : bucket k a =
182     let b, v = bucket::remove (b, ok) in
183     r := v;
184     b
185   in
186 
187   
188   array::update
189     [post = (x @ k * r @ ref (option a))] 
190     (t.buckets, key_index (t, x), remove);
191 
192   
193 
194   if !r then
195     t.cardinal <- t.cardinal - 1;
196   !r
197 
198 
199 
200 
201 
202 
203 
204 val mem [k, a] (x: k, t: table k a) : bool =
205   let equal = t.equal in
206   array::consult
207     [b = (bool | x @ k)]
208     
209     (t.buckets, key_index (t, x), fun (b: bucket k a | x @ k) : bool =
210       bucket::mem (equal, x, b)
211     )
212 
213 
214 
215 
216 val internal_find [k, a, answer] duplicable a => (
217   f: (bucket k a | x @ k) -> answer,
218   x: k,
219   t: table k a
220 ) : answer =
221   
222 
223   array::consult
224     [pre = (x @ k), b = (answer | x @ k)] 
225     (t.buckets, key_index (t, x), f)
226 
227 
228 
229 
230 val find [k, a] duplicable a => (x: k, t: table k a) : option a =
231   let equal = t.equal in
232   let f (b: bucket k a | x @ k) : option a =
233     bucket::assoc (equal, x, b)
234   in
235   internal_find (f, x, t)
236 
237 
238 
239 
240 val find_all [k, a] duplicable a => (x: k, t: table k a) : list::list a =
241   let equal = t.equal in
242   let f (b: bucket k a | x @ k) : list::list a =
243     bucket::assoc_all (equal, x, b)
244   in
245   internal_find (f, x, t)
246 
247 
248 
249 
250 
251 
252 
253 
254 
255 
256 
257 
258 val option_cardinal [a] (o: option a) : int =
259   match o with
260   | None -> 0
261   | Some -> 1
262   end
263 
264 val update [k, a, pre : perm, post : perm] (
265   t: table k a,
266   consumes x: k,
267   f: (consumes (option a | pre)) -> (option a | post)
268   | consumes pre
269 ) : (| post) =
270 
271   
272   let delta = newref () in
273   let f (consumes ov: option a | consumes (pre * delta @ ref ())) :
274         (option a | post * delta @ ref int) =
275     let decrease = option_cardinal ov in
276     let ov = f ov in
277     let increase = option_cardinal ov in
278     delta := increase - decrease;
279     ov
280   in
281 
282   
283   let equal = t.equal in
284   let update (consumes b: bucket k a | consumes (x @ k * pre * delta @ ref ())) : (bucket k a | post * delta @ ref int) =
285     bucket::update [post = (post * delta @ ref int)] (equal, b, x, f)
286     
287   in
288 
289   
290   array::update [post = (post * delta @ ref int)]
291     (t.buckets, key_index (t, x), update);
292     
293 
294 
295 
296   
297   t.cardinal <- t.cardinal + !delta
298 
299 
300 
301 
302 
303 
304 
305 
306 
307 
308 val fold [k, a, b] (
309   t: table k a,
310   consumes seed: b,
311   f: (k, a, consumes b) -> b
312 ) : b =
313   array::fold (Up, t.buckets, seed, fun (bck: bucket k a, consumes accu: b) : b =
314     bucket::fold (bck, accu, f)
315   )
316 
317 val iter [k, a, p : perm] (
318   t: table k a,
319   f: (k, a | p) -> ()
320   | p
321 ) : () =
322   fold [b=(| p)] (t, (), fun (x: k, v: a, (| p)) : () =
323     f (x, v)
324   )
325   
326 
327 
328 
329 
330 
331 val cardinal [k, a] (t: table k a) : int =
332   t.cardinal
333 
334 data statistics = Statistics {
335   num_bindings: int;
336   num_buckets: int;
337   max_bucket_length: int;
338   bucket_histogram: array int
339 }
340 
341 val stats [k, a] (t: table k a) : statistics =
342   
343   let mbl =
344     array::fold (Up, t.buckets, 0, fun (b: bucket k a, accu: int) : int =
345       max (bucket::length b, accu)
346     )
347   in
348   
349   let histo = array::create (mbl + 1, 0) in
350   array::iter (Up, t.buckets, fun (b: bucket k a | histo @ array int) : () =
351     let l = bucket::length b in
352     array::set (histo, l, array::get (histo, l) + 1)
353   );
354   
355   Statistics {
356     num_bindings = t.cardinal;
357     num_buckets  = array::length t.buckets;
358     max_bucket_length = mbl;
359     bucket_histogram = histo
360   }
361 
362 
363 
364 
365 
366