Source file miou_queue.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
type 'a t = { tail: 'a node Atomic.t; head: 'a node Atomic.t }
and 'a node = {
mutable value: 'a
; next: 'a node option Atomic.t
; mutable count: int
}
let enqueue t value =
let q = { value; next= Atomic.make None; count= 0 } in
let rec go () =
let p = Atomic.get t.tail in
q.count <- p.count + 1;
if Atomic.compare_and_set p.next None (Some q) then
ignore (Atomic.compare_and_set t.tail p q)
else
let[@warning "-8"] (Some next) = Atomic.get p.next in
let _ = Atomic.compare_and_set t.tail p next in
go ()
in
go ()
exception Empty
let dequeue t =
let rec go () =
let p = Atomic.get t.head in
match Atomic.get p.next with
| None -> raise Empty
| Some next ->
if Atomic.compare_and_set t.head p next then (
let value = next.value in
next.value <- Obj.magic ();
value)
else go ()
in
go ()
let peek t =
let p = Atomic.get t.head in
match Atomic.get p.next with None -> raise Empty | Some next -> next.value
let create () =
let dummy = { value= Obj.magic (); next= Atomic.make None; count= 0 } in
let t = { tail= Atomic.make dummy; head= Atomic.make dummy } in
assert (Atomic.get t.head == Atomic.get t.tail);
t
let is_empty t =
let p = Atomic.get t.head in
match Atomic.get p.next with None -> true | Some _ -> false
type 'a snapshot = 'a node * 'a node
let rec snapshot t : 'a snapshot =
let head = Atomic.get t.head and tail = Atomic.get t.tail in
match Atomic.get tail.next with
| Some node ->
let _ = Atomic.compare_and_set t.tail tail node in
snapshot t
| None ->
if Atomic.get (Sys.opaque_identity t.head) != head then snapshot t
else (head, tail)
let length t =
let head, tail = snapshot t in
tail.count - head.count
let iter ~f (head, tail) =
let rec go prev =
if prev != tail then
match Atomic.get prev.next with
| None -> ()
| Some next -> f next.value; go next
in
go head
let rec drop t =
let ((head, tail) as snapshot) = snapshot t in
if Atomic.compare_and_set t.head head tail then snapshot else drop t
let drop ~f t = iter ~f (drop t)
let iter ~f t = iter ~f (snapshot t)
let to_list t =
let res = ref [] in
let f v = res := v :: !res in
iter ~f t; List.rev !res
let transfer t =
let q = create () in
drop ~f:(fun x -> enqueue q x) t;
q