Source file stamped_hashtable.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
type cell =
Cell : {
stamp: int;
table: ('a, 'b) Hashtbl.t;
key: 'a;
} -> cell
type changelog = {
mutable recent: cell list;
mutable sorted: cell list;
}
let create_changelog () = {
recent = [];
sorted = [];
}
type ('a, 'b) t = {
table: ('a, 'b) Hashtbl.t;
changelog: changelog;
}
let create changelog n = {
table = Hashtbl.create n;
changelog;
}
let add {table; changelog} ?stamp key value =
Hashtbl.add table key value;
match stamp with
| None -> ()
| Some stamp ->
changelog.recent <- Cell {stamp; key; table} :: changelog.recent
let replace t k v =
Hashtbl.replace t.table k v
let mem t a =
Hashtbl.mem t.table a
let find t a =
Hashtbl.find t.table a
let fold f t acc =
Hashtbl.fold f t.table acc
let clear t =
Hashtbl.clear t.table;
t.changelog.recent <- [];
t.changelog.sorted <- []
let order (Cell c1) (Cell c2) =
Int.compare c2.stamp c1.stamp
let rec filter_prefix pred = function
| x :: xs when not (pred x) ->
filter_prefix pred xs
| xs -> xs
let backtrack cs ~stamp =
let process (Cell c) =
if c.stamp > stamp then (
Hashtbl.remove c.table c.key;
false
) else
true
in
let recent =
cs.recent
|> List.filter process
|> List.fast_sort order
in
cs.recent <- [];
let sorted =
cs.sorted
|> filter_prefix process
|> List.merge order recent
in
cs.sorted <- sorted