@@ -31,13 +31,26 @@ type ('a, 'b) t =
31
31
{ mutable size : int ; (* number of entries *)
32
32
mutable data : ('a , 'b ) bucketlist array ; (* the buckets *)
33
33
mutable seed : int ; (* for randomization *)
34
- initial_size : int ; (* initial array size *)
34
+ mutable initial_size : int ; (* initial array size *)
35
35
}
36
36
37
37
and ('a, 'b) bucketlist =
38
38
Empty
39
39
| Cons of { mutable key : 'a ; mutable data : 'b ; mutable next : ('a , 'b ) bucketlist }
40
40
41
+ (* The sign of initial_size encodes the fact that a traversal is
42
+ ongoing or not.
43
+
44
+ This disables the efficient in place implementation of resizing.
45
+ *)
46
+
47
+ let ongoing_traversal h =
48
+ Obj. size (Obj. repr h) < 4 (* compatibility with old hash tables *)
49
+ || h.initial_size < 0
50
+
51
+ let flip_ongoing_traversal h =
52
+ h.initial_size < - - h.initial_size
53
+
41
54
(* To pick random seeds if requested *)
42
55
43
56
let randomized_default =
@@ -75,11 +88,11 @@ let clear h =
75
88
let reset h =
76
89
let len = Array. length h.data in
77
90
if Obj. size (Obj. repr h) < 4 (* compatibility with old hash tables *)
78
- || len = h.initial_size then
91
+ || len = abs h.initial_size then
79
92
clear h
80
93
else begin
81
94
h.size < - 0 ;
82
- h.data < - Array. make h.initial_size Empty
95
+ h.data < - Array. make (abs h.initial_size) Empty
83
96
end
84
97
85
98
let copy_bucketlist = function
@@ -110,10 +123,15 @@ let resize indexfun h =
110
123
if nsize < Sys. max_array_length then begin
111
124
let ndata = Array. make nsize Empty in
112
125
let ndata_tail = Array. make nsize Empty in
126
+ let inplace = not (ongoing_traversal h) in
113
127
h.data < - ndata; (* so that indexfun sees the new bucket count *)
114
128
let rec insert_bucket = function
115
129
| Empty -> ()
116
- | Cons {key; next} as cell ->
130
+ | Cons {key; data; next} as cell ->
131
+ let cell =
132
+ if inplace then cell
133
+ else Cons {key; data; next = Empty }
134
+ in
117
135
let nidx = indexfun h key in
118
136
begin match ndata_tail.(nidx) with
119
137
| Empty -> ndata.(nidx) < - cell;
@@ -125,11 +143,12 @@ let resize indexfun h =
125
143
for i = 0 to osize - 1 do
126
144
insert_bucket odata.(i)
127
145
done ;
128
- for i = 0 to nsize - 1 do
129
- match ndata_tail.(i) with
130
- | Empty -> ()
131
- | Cons tail -> tail.next < - Empty
132
- done ;
146
+ if inplace then
147
+ for i = 0 to nsize - 1 do
148
+ match ndata_tail.(i) with
149
+ | Empty -> ()
150
+ | Cons tail -> tail.next < - Empty
151
+ done ;
133
152
end
134
153
135
154
let key_index h key =
@@ -223,10 +242,17 @@ let iter f h =
223
242
()
224
243
| Cons {key; data; next} ->
225
244
f key data; do_bucket next in
226
- let d = h.data in
227
- for i = 0 to Array. length d - 1 do
228
- do_bucket d.(i)
229
- done
245
+ let old_trav = ongoing_traversal h in
246
+ if not old_trav then flip_ongoing_traversal h;
247
+ try
248
+ let d = h.data in
249
+ for i = 0 to Array. length d - 1 do
250
+ do_bucket d.(i)
251
+ done ;
252
+ if not old_trav then flip_ongoing_traversal h;
253
+ with exn when not old_trav ->
254
+ flip_ongoing_traversal h;
255
+ raise exn
230
256
231
257
let filter_map_inplace f h =
232
258
let rec do_bucket = function
@@ -249,12 +275,19 @@ let fold f h init =
249
275
accu
250
276
| Cons {key; data; next} ->
251
277
do_bucket next (f key data accu) in
252
- let d = h.data in
253
- let accu = ref init in
254
- for i = 0 to Array. length d - 1 do
255
- accu := do_bucket d.(i) ! accu
256
- done ;
257
- ! accu
278
+ let old_trav = ongoing_traversal h in
279
+ if not old_trav then flip_ongoing_traversal h;
280
+ try
281
+ let d = h.data in
282
+ let accu = ref init in
283
+ for i = 0 to Array. length d - 1 do
284
+ accu := do_bucket d.(i) ! accu
285
+ done ;
286
+ if not old_trav then flip_ongoing_traversal h;
287
+ ! accu
288
+ with exn when not old_trav ->
289
+ flip_ongoing_traversal h;
290
+ raise exn
258
291
259
292
type statistics = {
260
293
num_bindings : int ;
0 commit comments