Skip to content

Commit 4511b93

Browse files
committed
Use polymorphic variants to avoid the impossible
1 parent 6925c2b commit 4511b93

File tree

1 file changed

+37
-45
lines changed

1 file changed

+37
-45
lines changed

src/michael_scott_queue.ml

Lines changed: 37 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -18,70 +18,63 @@
1818

1919
(* Michael-Scott queue *)
2020

21-
type 'a node = Nil | Next of 'a * 'a node Atomic.t
22-
type 'a t = { head : 'a node Atomic.t; tail : 'a node Atomic.t Atomic.t }
21+
type 'a node = 'a * [ `Nil | `Node of 'a node ] Atomic.t
22+
23+
type 'a t = {
24+
head : [ `Node of 'a node ] Atomic.t;
25+
tail : [ `Nil | `Node of 'a node ] Atomic.t Atomic.t;
26+
}
2327

2428
let create () =
25-
let tail = Atomic.make Nil in
26-
let head = Next (Obj.magic (), tail) in
29+
let tail = Atomic.make `Nil in
30+
let head = `Node (Obj.magic (), tail) in
2731
{ head = Atomic.make head; tail = Atomic.make tail }
2832

29-
let is_empty q =
30-
match Atomic.get q.head with
31-
| Nil -> failwith "MSQueue.is_empty: impossible"
32-
| Next (_, x) -> ( match Atomic.get x with Nil -> true | _ -> false)
33+
let is_empty { head; _ } =
34+
let (`Node (_, x)) = Atomic.get head in
35+
Atomic.get x == `Nil
3336

34-
let pop q =
37+
let pop { head; _ } =
3538
let b = Backoff.create () in
3639
let rec loop () =
37-
let s = Atomic.get q.head in
38-
let nhead =
39-
match s with
40-
| Nil -> failwith "MSQueue.pop: impossible"
41-
| Next (_, x) -> Atomic.get x
42-
in
43-
match nhead with
44-
| Nil -> None
45-
| Next (v, x) when Atomic.compare_and_set q.head s (Next (Obj.magic (), x))
46-
->
40+
let (`Node (_, x) as old_head) = Atomic.get head in
41+
match Atomic.get x with
42+
| `Nil -> None
43+
| `Node (v, x)
44+
when Atomic.compare_and_set head old_head (`Node (Obj.magic (), x)) ->
4745
Some v
4846
| _ ->
4947
Backoff.once b;
5048
loop ()
5149
in
5250
loop ()
5351

54-
let push q v =
52+
let push { tail; _ } v =
5553
let rec find_tail_and_enq curr_end node =
56-
if Atomic.compare_and_set curr_end Nil node then ()
54+
if Atomic.compare_and_set curr_end `Nil node then ()
5755
else
5856
match Atomic.get curr_end with
59-
| Nil -> find_tail_and_enq curr_end node
60-
| Next (_, n) ->
57+
| `Nil -> find_tail_and_enq curr_end node
58+
| `Node (_, n) ->
6159
(* If tail falls behind, there is a risk of space leak. *)
62-
ignore (Atomic.compare_and_set q.tail curr_end n);
60+
ignore (Atomic.compare_and_set tail curr_end n);
6361
find_tail_and_enq n node
6462
in
65-
let new_tail = Atomic.make Nil in
66-
let newnode = Next (v, new_tail) in
67-
let old_tail = Atomic.get q.tail in
63+
let new_tail = Atomic.make `Nil in
64+
let newnode = `Node (v, new_tail) in
65+
let old_tail = Atomic.get tail in
6866
find_tail_and_enq old_tail newnode;
69-
ignore (Atomic.compare_and_set q.tail old_tail new_tail)
67+
ignore (Atomic.compare_and_set tail old_tail new_tail)
7068

71-
let clean_until q f =
69+
let clean_until { head; _ } f =
7270
let b = Backoff.create () in
7371
let rec loop () =
74-
let s = Atomic.get q.head in
75-
let nhead =
76-
match s with
77-
| Nil -> failwith "MSQueue.pop: impossible"
78-
| Next (_, x) -> Atomic.get x
79-
in
80-
match nhead with
81-
| Nil -> ()
82-
| Next (v, x) ->
72+
let (`Node (_, x) as old_head) = Atomic.get head in
73+
match Atomic.get x with
74+
| `Nil -> ()
75+
| `Node (v, x) ->
8376
if not (f v) then
84-
if Atomic.compare_and_set q.head s (Next (Obj.magic (), x)) then (
77+
if Atomic.compare_and_set head old_head (`Node (Obj.magic (), x)) then (
8578
Backoff.reset b;
8679
loop ())
8780
else (
@@ -91,11 +84,10 @@ let clean_until q f =
9184
in
9285
loop ()
9386

94-
type 'a cursor = 'a node
87+
type 'a cursor = [ `Nil | `Node of 'a node ]
9588

96-
let snapshot q =
97-
match Atomic.get q.head with
98-
| Nil -> failwith "MSQueue.snapshot: impossible"
99-
| Next (_, n) -> Atomic.get n
89+
let snapshot { head; _ } =
90+
let (`Node (_, n)) = Atomic.get head in
91+
Atomic.get n
10092

101-
let next c = match c with Nil -> None | Next (a, n) -> Some (a, Atomic.get n)
93+
let next = function `Nil -> None | `Node (a, n) -> Some (a, Atomic.get n)

0 commit comments

Comments
 (0)