Skip to content

Commit 3ca2639

Browse files
committed
Use polymorphic variants to avoid the impossible
1 parent 821340d commit 3ca2639

File tree

1 file changed

+36
-44
lines changed

1 file changed

+36
-44
lines changed

src/michael_scott_queue.ml

Lines changed: 36 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -17,67 +17,60 @@
1717

1818
(* Michael-Scott queue *)
1919

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

2327
let create () =
24-
let tail = Atomic.make Nil in
25-
let head = Next (Obj.magic (), tail) in
28+
let tail = Atomic.make `Nil in
29+
let head = `Node (Obj.magic (), tail) in
2630
{ head = Atomic.make head; tail = Atomic.make tail }
2731

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

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

53-
let push q v =
51+
let push { tail; _ } v =
5452
let rec find_tail_and_enq curr_end node =
55-
if Atomic.compare_and_set curr_end Nil node then ()
53+
if Atomic.compare_and_set curr_end `Nil node then ()
5654
else
5755
match Atomic.get curr_end with
58-
| Nil -> find_tail_and_enq curr_end node
59-
| Next (_, n) -> find_tail_and_enq n node
56+
| `Nil -> find_tail_and_enq curr_end node
57+
| `Node (_, n) -> find_tail_and_enq n node
6058
in
61-
let new_tail = Atomic.make Nil in
62-
let newnode = Next (v, new_tail) in
63-
let old_tail = Atomic.get q.tail in
59+
let new_tail = Atomic.make `Nil in
60+
let newnode = `Node (v, new_tail) in
61+
let old_tail = Atomic.get tail in
6462
find_tail_and_enq old_tail newnode;
65-
ignore (Atomic.compare_and_set q.tail old_tail new_tail)
63+
ignore (Atomic.compare_and_set tail old_tail new_tail)
6664

67-
let clean_until q f =
65+
let clean_until { head; _ } f =
6866
let b = Backoff.create () in
6967
let rec loop () =
70-
let s = Atomic.get q.head in
71-
let nhead =
72-
match s with
73-
| Nil -> failwith "MSQueue.pop: impossible"
74-
| Next (_, x) -> Atomic.get x
75-
in
76-
match nhead with
77-
| Nil -> ()
78-
| Next (v, x) ->
68+
let (`Node (_, x) as old_head) = Atomic.get head in
69+
match Atomic.get x with
70+
| `Nil -> ()
71+
| `Node (v, x) ->
7972
if not (f v) then
80-
if Atomic.compare_and_set q.head s (Next (Obj.magic (), x)) then (
73+
if Atomic.compare_and_set head old_head (`Node (Obj.magic (), x)) then (
8174
Backoff.reset b;
8275
loop ())
8376
else (
@@ -87,11 +80,10 @@ let clean_until q f =
8780
in
8881
loop ()
8982

90-
type 'a cursor = 'a node
83+
type 'a cursor = [ `Nil | `Node of 'a node ]
9184

92-
let snapshot q =
93-
match Atomic.get q.head with
94-
| Nil -> failwith "MSQueue.snapshot: impossible"
95-
| Next (_, n) -> Atomic.get n
85+
let snapshot { head; _ } =
86+
let (`Node (_, n)) = Atomic.get head in
87+
Atomic.get n
9688

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

0 commit comments

Comments
 (0)