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