Source file thread_table.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
type 'v bucket = Nil | Cons of int * 'v * 'v bucket
type 'v t = {
mutable rehash : int;
mutable buckets : 'v bucket array;
mutable length : int;
}
let[@tail_mod_cons] rec remove_first removed k' = function
| Nil -> Nil
| Cons (k, v, kvs) ->
if k == k' then begin
removed := true;
kvs
end
else Cons (k, v, remove_first removed k' kvs)
let[@inline] remove_first removed k' = function
| Nil -> Nil
| Cons (k, v, kvs) ->
if k == k' then begin
removed := true;
kvs
end
else Cons (k, v, remove_first removed k' kvs)
let rec find k' = function
| Nil -> raise_notrace Not_found
| Cons (k, v, kvs) -> if k == k' then v else find k' kvs
let[@tail_mod_cons] rec filter bit chk = function
| Nil -> Nil
| Cons (k, v, kvs) ->
if Mix.int k land bit = chk then Cons (k, v, filter bit chk kvs)
else filter bit chk kvs
let[@inline] filter bit chk = function
| Nil -> Nil
| Cons (k, _, Nil) as kvs -> if Mix.int k land bit = chk then kvs else Nil
| Cons (k, v, kvs) ->
if Mix.int k land bit = chk then Cons (k, v, filter bit chk kvs)
else filter bit chk kvs
let[@tail_mod_cons] rec append kvs tail =
match kvs with Nil -> tail | Cons (k, v, kvs) -> Cons (k, v, append kvs tail)
let[@inline] append kvs tail =
match kvs with Nil -> tail | Cons (k, v, kvs) -> Cons (k, v, append kvs tail)
let min_buckets = 4
and max_buckets_div_2 = (Sys.max_array_length + 1) asr 1
let create () = { rehash = 0; buckets = Array.make min_buckets Nil; length = 0 }
let length t = t.length
let find t k' =
let h = Mix.int k' in
let buckets = t.buckets in
let n = Array.length buckets in
let i = h land (n - 1) in
find k' (Array.unsafe_get buckets i)
let[@poll error] [@inline never] update_buckets_atomically t old_buckets
new_buckets =
t.buckets == old_buckets
&& begin
t.buckets <- new_buckets;
t.rehash <- 0;
true
end
let rec maybe_rehash t =
let old_buckets = t.buckets in
let new_n = t.rehash in
if new_n <> 0 then
let old_n = Array.length old_buckets in
let new_buckets = Array.make new_n Nil in
if old_n * 2 = new_n then
let new_bit = new_n lsr 1 in
let rec loop i =
if t.buckets == old_buckets then
if old_n <= i then begin
if not (update_buckets_atomically t old_buckets new_buckets) then
maybe_rehash t
end
else begin
let kvs = Array.unsafe_get old_buckets i in
Array.unsafe_set new_buckets i (filter new_bit 0 kvs);
Array.unsafe_set new_buckets (i lor new_bit)
(filter new_bit new_bit kvs);
loop (i + 1)
end
else maybe_rehash t
in
loop 0
else if old_n = new_n * 2 then
let old_bit = old_n lsr 1 in
let rec loop i =
if t.buckets == old_buckets then
if new_n <= i then begin
if not (update_buckets_atomically t old_buckets new_buckets) then
maybe_rehash t
end
else begin
Array.unsafe_set new_buckets i
(append
(Array.unsafe_get old_buckets (i + old_bit))
(Array.unsafe_get old_buckets i));
loop (i + 1)
end
else maybe_rehash t
in
loop 0
else maybe_rehash t
let[@inline] maybe_rehash t = if t.rehash <> 0 then maybe_rehash t
let[@poll error] [@inline never] add_atomically t buckets n i before after =
t.rehash = 0 && buckets == t.buckets
&& before == Array.unsafe_get buckets i
&& begin
Array.unsafe_set buckets i after;
let length = t.length + 1 in
t.length <- length;
if n < length && n < max_buckets_div_2 then t.rehash <- n * 2;
true
end
let rec add t k' v' =
let h = Mix.int k' in
maybe_rehash t;
let buckets = t.buckets in
let n = Array.length buckets in
let i = h land (n - 1) in
let before = Array.unsafe_get buckets i in
let after = Cons (k', v', before) in
if not (add_atomically t buckets n i before after) then add t k' v'
let[@poll error] [@inline never] remove_atomically t buckets n i before after
removed =
t.rehash = 0 && buckets == t.buckets
&& before == Array.unsafe_get buckets i
&& ((not !removed)
|| begin
Array.unsafe_set buckets i after;
let length = t.length - 1 in
t.length <- length;
if length * 4 < n && min_buckets < n then t.rehash <- n asr 1;
true
end)
let rec remove t k' =
let h = Mix.int k' in
let removed = ref false in
maybe_rehash t;
let buckets = t.buckets in
let n = Array.length buckets in
let i = h land (n - 1) in
let before = Array.unsafe_get buckets i in
let after = remove_first removed k' before in
if not (remove_atomically t buckets n i before after removed) then remove t k'