Skip to content

Commit 23b2edf

Browse files
committed
Keep track of whether a traversal is ongoing and in this case, disables the inplace implementation of resizing.
1 parent 7394676 commit 23b2edf

File tree

1 file changed

+52
-19
lines changed

1 file changed

+52
-19
lines changed

stdlib/hashtbl.ml

+52-19
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,26 @@ type ('a, 'b) t =
3131
{ mutable size: int; (* number of entries *)
3232
mutable data: ('a, 'b) bucketlist array; (* the buckets *)
3333
mutable seed: int; (* for randomization *)
34-
initial_size: int; (* initial array size *)
34+
mutable initial_size: int; (* initial array size *)
3535
}
3636

3737
and ('a, 'b) bucketlist =
3838
Empty
3939
| Cons of { mutable key: 'a; mutable data: 'b; mutable next: ('a, 'b) bucketlist }
4040

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+
4154
(* To pick random seeds if requested *)
4255

4356
let randomized_default =
@@ -75,11 +88,11 @@ let clear h =
7588
let reset h =
7689
let len = Array.length h.data in
7790
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
7992
clear h
8093
else begin
8194
h.size <- 0;
82-
h.data <- Array.make h.initial_size Empty
95+
h.data <- Array.make (abs h.initial_size) Empty
8396
end
8497

8598
let copy_bucketlist = function
@@ -110,10 +123,15 @@ let resize indexfun h =
110123
if nsize < Sys.max_array_length then begin
111124
let ndata = Array.make nsize Empty in
112125
let ndata_tail = Array.make nsize Empty in
126+
let inplace = not (ongoing_traversal h) in
113127
h.data <- ndata; (* so that indexfun sees the new bucket count *)
114128
let rec insert_bucket = function
115129
| 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
117135
let nidx = indexfun h key in
118136
begin match ndata_tail.(nidx) with
119137
| Empty -> ndata.(nidx) <- cell;
@@ -125,11 +143,12 @@ let resize indexfun h =
125143
for i = 0 to osize - 1 do
126144
insert_bucket odata.(i)
127145
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;
133152
end
134153

135154
let key_index h key =
@@ -223,10 +242,17 @@ let iter f h =
223242
()
224243
| Cons{key; data; next} ->
225244
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
230256

231257
let filter_map_inplace f h =
232258
let rec do_bucket = function
@@ -249,12 +275,19 @@ let fold f h init =
249275
accu
250276
| Cons{key; data; next} ->
251277
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
258291

259292
type statistics = {
260293
num_bindings: int;

0 commit comments

Comments
 (0)