-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathtwo_stack_queue.ml
More file actions
143 lines (122 loc) · 4.24 KB
/
Copy pathtwo_stack_queue.ml
File metadata and controls
143 lines (122 loc) · 4.24 KB
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
135
136
137
138
139
140
141
142
143
open Kcas
type 'a t = { head : 'a head Loc.t; tail : 'a tail Loc.t }
and ('a, _) tdt =
| Cons : {
counter : int;
value : 'a;
suffix : 'a head;
}
-> ('a, [> `Cons ]) tdt
| Head : { counter : int } -> ('a, [> `Head ]) tdt
| Snoc : {
counter : int;
prefix : 'a tail;
value : 'a;
}
-> ('a, [> `Snoc ]) tdt
| Tail : {
counter : int;
mutable move : ('a, [ `Snoc | `Used ]) tdt;
}
-> ('a, [> `Tail ]) tdt
| Used : ('a, [> `Used ]) tdt
and 'a head = H : ('a, [< `Cons | `Head ]) tdt -> 'a head [@@unboxed]
and 'a tail = T : ('a, [< `Snoc | `Tail ]) tdt -> 'a tail [@@unboxed]
(* *)
let create () =
let head = Loc.make ~padded:true (H (Head { counter = 1 })) in
let tail = Loc.make ~padded:true (T (Tail { counter = 0; move = Used })) in
{ head; tail } |> Multicore_magic.copy_as_padded
(* *)
let rec rev (suffix : (_, [< `Cons ]) tdt) = function
| T (Snoc { counter; prefix; value }) ->
rev (Cons { counter; value; suffix = H suffix }) prefix
| T (Tail _) -> suffix
let[@inline] rev = function
| (Snoc { counter; prefix; value } : (_, [< `Snoc ]) tdt) ->
rev
(Cons { counter; value; suffix = H (Head { counter = counter + 1 }) })
prefix
(* *)
let rec push backoff t value =
match Loc.fenceless_get t.tail with
| T (Snoc snoc_r) as prefix -> push_with backoff t snoc_r.counter prefix value
| T (Tail tail_r as tail) ->
begin
match tail_r.move with
| Used -> ()
| Snoc move_r as move -> begin
match Loc.fenceless_get t.head with
| H (Head head_r as head) when head_r.counter < move_r.counter ->
let after = rev move in
if Loc.compare_and_set t.head (H head) (H after) then
tail_r.move <- Used
| _ -> ()
end
end;
push_with backoff t tail_r.counter (T tail) value
and push_with backoff t counter prefix value =
let after = Snoc { counter = counter + 1; prefix; value } in
if not (Loc.compare_and_set t.tail prefix (T after)) then
push (Backoff.once backoff) t value
let[@inline] push t value = push Backoff.default t value
(* *)
exception Empty
let rec pop backoff t =
match Loc.get t.head with
| H (Cons cons_r) as before ->
let after = cons_r.suffix in
if Loc.compare_and_set t.head before after then cons_r.value
else pop (Backoff.once backoff) t
| H (Head head_r as head) -> begin
match Loc.fenceless_get t.tail with
| T (Snoc snoc_r as move) ->
if head_r.counter = snoc_r.counter then
if Loc.compare_and_set t.tail (T move) snoc_r.prefix then
snoc_r.value
else pop backoff t
else
let tail = Tail { counter = snoc_r.counter; move } in
if
Loc.fenceless_get t.head == H head
&& Loc.compare_and_set t.tail (T move) (T tail)
then pop_moving backoff t head move tail
else pop backoff t
| T (Tail tail_r as tail) -> begin
match tail_r.move with
| Used -> pop_emptyish backoff t head
| Snoc _ as move -> pop_moving backoff t head move tail
end
end
and pop_moving backoff t (Head head_r as head : (_, [< `Head ]) tdt)
(Snoc move_r as move : (_, [< `Snoc ]) tdt)
(Tail tail_r : (_, [< `Tail ]) tdt) =
if head_r.counter < move_r.counter then
match rev move with
| Cons cons_r ->
if Loc.compare_and_set t.head (H head) cons_r.suffix then begin
tail_r.move <- Used;
cons_r.value
end
else pop (Backoff.once backoff) t
else pop_emptyish backoff t head
and pop_emptyish backoff t head =
if Loc.get t.head == H head then raise_notrace Empty else pop backoff t
let[@inline] pop_opt t =
match pop Backoff.default t with
| value -> Some value
| exception Empty -> None
let[@inline] pop t = pop Backoff.default t
(* *)
let rec length t =
let head = Loc.get t.head in
let tail = Loc.fenceless_get t.tail in
if head != Loc.get t.head then length t
else
let head_at =
match head with H (Cons r) -> r.counter | H (Head r) -> r.counter
in
let tail_at =
match tail with T (Snoc r) -> r.counter | T (Tail r) -> r.counter
in
tail_at - head_at + 1