@@ -2,127 +2,172 @@ open Kcas
2
2
3
3
type 'a t = {
4
4
front : 'a Elems .t Loc .t ;
5
- middle : 'a Elems .t Loc .t ;
6
- back : 'a Elems .t Loc .t ;
5
+ back : 'a List_with_capacity .t Loc .t ;
6
+ middle : 'a List_with_capacity .t Loc .t ;
7
7
}
8
8
9
- let alloc ~front ~middle ~ back =
9
+ let alloc ~front ~back ~ middle =
10
10
(* We allocate locations in specific order to make most efficient use of the
11
11
splay-tree based transaction log. *)
12
12
let front = Loc. make front
13
- and middle = Loc. make middle
14
- and back = Loc. make back in
13
+ and back = Loc. make back
14
+ and middle = Loc. make middle in
15
15
{ back; middle; front }
16
16
17
- let create () = alloc ~front: Elems. empty ~middle: Elems. empty ~back: Elems. empty
17
+ let create ?(capacity = Int. max_int) () =
18
+ if capacity < 0 then invalid_arg " Queue.create: capacity must be non-negative" ;
19
+ let back = List_with_capacity. make_empty ~capacity in
20
+ alloc ~front: Elems. empty ~back ~middle: List_with_capacity. empty_unlimited
18
21
19
22
let copy q =
20
- let tx ~xt = (Xt. get ~xt q.front, Xt. get ~xt q.middle , Xt. get ~xt q.back ) in
21
- let front, middle, back = Xt. commit { tx } in
22
- alloc ~front ~middle ~back
23
+ let tx ~xt = (Xt. get ~xt q.front, Xt. get ~xt q.back , Xt. get ~xt q.middle ) in
24
+ let front, back, middle = Xt. commit { tx } in
25
+ alloc ~front ~back ~middle
23
26
24
27
module Xt = struct
25
- let is_empty ~xt { back; middle; front } =
28
+ let is_empty ~xt q =
26
29
(* We access locations in order of allocation to make most efficient use of
27
30
the splay-tree based transaction log. *)
28
- Xt. get ~xt front == Elems. empty
29
- && Xt. get ~xt middle == Elems. empty
30
- && Xt. get ~xt back == Elems. empty
31
-
32
- let length ~xt { back; middle; front } =
33
- Elems. length (Xt. get ~xt front)
34
- + Elems. length (Xt. get ~xt middle)
35
- + Elems. length (Xt. get ~xt back)
36
-
37
- let add ~xt x q = Xt. unsafe_modify ~xt q.back @@ Elems. cons x
31
+ Xt. get ~xt q.front == Elems. empty
32
+ && List_with_capacity. is_empty (Xt. get ~xt q.back)
33
+ && Xt. get ~xt q.middle == List_with_capacity. empty_unlimited
34
+
35
+ let length ~xt q =
36
+ Elems. length (Xt. get ~xt q.front)
37
+ + List_with_capacity. length (Xt. get ~xt q.back)
38
+ + List_with_capacity. length (Xt. get ~xt q.middle)
39
+
40
+ let try_add ~xt x q =
41
+ let lwc = Xt. unsafe_update ~xt q.back (List_with_capacity. cons_safe x) in
42
+ let capacity = List_with_capacity. capacity lwc in
43
+ capacity = Int. max_int
44
+ ||
45
+ let back_length = List_with_capacity. length lwc in
46
+ back_length < List_with_capacity. limit lwc
47
+ ||
48
+ let other_length =
49
+ List_with_capacity. length (Xt. get ~xt q.middle)
50
+ + Elems. length (Xt. get ~xt q.front)
51
+ in
52
+ let limit = capacity - other_length in
53
+ back_length < limit
54
+ &&
55
+ (Xt. set ~xt q.back
56
+ (List_with_capacity. make ~capacity ~length: (back_length + 1 )
57
+ ~list: (x :: List_with_capacity. list lwc)
58
+ ~limit );
59
+ true )
60
+
61
+ let add ~xt x q = Retry. unless (try_add ~xt x q)
38
62
let push = add
39
63
40
64
(* * Cooperative helper to move elems from back to middle. *)
41
- let back_to_middle ~middle ~ back =
65
+ let back_to_middle ~back ~ middle =
42
66
let tx ~xt =
43
- let xs = Xt. exchange ~xt back Elems. empty in
44
- if xs == Elems. empty || Xt. exchange ~xt middle xs != Elems. empty then
45
- raise Exit
67
+ let xs = Xt. unsafe_update ~xt back List_with_capacity. move in
68
+ if
69
+ List_with_capacity. length xs = 0
70
+ || Xt. exchange ~xt middle xs != List_with_capacity. empty_unlimited
71
+ then raise Exit
46
72
in
47
73
try Xt. commit { tx } with Exit -> ()
48
74
49
- let take_opt_finish ~xt front elems =
50
- let elems = Elems. rev elems in
75
+ let take_opt_finish ~xt front lwc =
76
+ let elems = List_with_capacity. to_rev_elems lwc in
51
77
Xt. set ~xt front (Elems. tl_safe elems);
52
78
Elems. hd_opt elems
53
79
54
- let take_opt ~xt { back; middle; front } =
80
+ let take_opt ~xt { front; back; middle } =
55
81
let elems = Xt. unsafe_update ~xt front Elems. tl_safe in
56
82
if elems != Elems. empty then Elems. hd_opt elems
57
83
else (
58
84
if not (Xt. is_in_log ~xt middle || Xt. is_in_log ~xt back) then
59
- back_to_middle ~middle ~back ;
60
- let elems = Xt. exchange ~xt middle Elems. empty in
61
- if elems != Elems. empty then take_opt_finish ~xt front elems
85
+ back_to_middle ~back ~middle ;
86
+ let lwc = Xt. exchange ~xt middle List_with_capacity. empty_unlimited in
87
+ if lwc != List_with_capacity. empty_unlimited then
88
+ take_opt_finish ~xt front lwc
62
89
else
63
- let elems = Xt. exchange ~xt back Elems. empty in
64
- if elems != Elems. empty then take_opt_finish ~xt front elems else None )
90
+ let lwc = Xt. unsafe_update ~xt back List_with_capacity. move in
91
+ if List_with_capacity. length lwc <> 0 then take_opt_finish ~xt front lwc
92
+ else None )
65
93
66
94
let take_blocking ~xt q = Xt. to_blocking ~xt (take_opt q)
67
95
68
- let peek_opt_finish ~xt front elems =
69
- let elems = Elems. rev elems in
96
+ let peek_opt_finish ~xt front lwc =
97
+ let elems = List_with_capacity. to_rev_elems lwc in
70
98
Xt. set ~xt front elems;
71
99
Elems. hd_opt elems
72
100
73
- let peek_opt ~xt { back; middle; front } =
101
+ let peek_opt ~xt { front; back; middle } =
74
102
let elems = Xt. get ~xt front in
75
103
if elems != Elems. empty then Elems. hd_opt elems
76
104
else (
77
105
if not (Xt. is_in_log ~xt middle || Xt. is_in_log ~xt back) then
78
- back_to_middle ~middle ~back ;
79
- let elems = Xt. exchange ~xt middle Elems. empty in
80
- if elems != Elems. empty then peek_opt_finish ~xt front elems
106
+ back_to_middle ~back ~middle ;
107
+ let lwc = Xt. exchange ~xt middle List_with_capacity. empty_unlimited in
108
+ if lwc != List_with_capacity. empty_unlimited then
109
+ peek_opt_finish ~xt front lwc
81
110
else
82
- let elems = Xt. exchange ~xt back Elems. empty in
83
- if elems != Elems. empty then peek_opt_finish ~xt front elems else None )
111
+ let lwc = Xt. unsafe_update ~xt back List_with_capacity. move in
112
+ if List_with_capacity. length lwc <> 0 then peek_opt_finish ~xt front lwc
113
+ else None )
84
114
85
115
let peek_blocking ~xt q = Xt. to_blocking ~xt (peek_opt q)
86
116
87
- let clear ~xt { back; middle; front } =
88
- Xt. set ~xt front Elems. empty;
89
- Xt. set ~xt middle Elems. empty ;
90
- Xt. set ~xt back Elems. empty
117
+ let clear ~xt q =
118
+ Xt. set ~xt q. front Elems. empty;
119
+ Xt. unsafe_modify ~xt q.back List_with_capacity. clear ;
120
+ Xt. set ~xt q.middle List_with_capacity. empty_unlimited
91
121
92
122
let swap ~xt q1 q2 =
93
123
let front = Xt. get ~xt q1.front
94
- and middle = Xt. get ~xt q1.middle
95
- and back = Xt. get ~xt q1.back in
124
+ and back = Xt. get ~xt q1.back
125
+ and middle = Xt. get ~xt q1.middle in
96
126
let front = Xt. exchange ~xt q2.front front
97
- and middle = Xt. exchange ~xt q2.middle middle
98
- and back = Xt. exchange ~xt q2.back back in
127
+ and back = Xt. exchange ~xt q2.back back
128
+ and middle = Xt. exchange ~xt q2.middle middle in
99
129
Xt. set ~xt q1.front front;
100
- Xt. set ~xt q1.middle middle ;
101
- Xt. set ~xt q1.back back
130
+ Xt. set ~xt q1.back back ;
131
+ Xt. set ~xt q1.middle middle
102
132
103
133
let seq_of ~front ~middle ~back =
104
134
(* Sequence construction is lazy, so this function is O(1). *)
105
135
Seq. empty
106
- |> Elems . rev_prepend_to_seq back
107
- |> Elems . rev_prepend_to_seq middle
136
+ |> List_with_capacity . rev_prepend_to_seq back
137
+ |> List_with_capacity . rev_prepend_to_seq middle
108
138
|> Elems. prepend_to_seq front
109
139
110
- let to_seq ~xt { front; middle; back } =
111
- let front = Xt. get ~xt front
112
- and middle = Xt. get ~xt middle
113
- and back = Xt. get ~xt back in
140
+ let to_seq ~xt q =
141
+ let front = Xt. get ~xt q. front
142
+ and back = Xt. get ~xt q.back
143
+ and middle = Xt. get ~xt q.middle in
114
144
seq_of ~front ~middle ~back
115
145
116
- let take_all ~xt { front; middle; back } =
117
- let front = Xt. exchange ~xt front Elems. empty
118
- and middle = Xt. exchange ~xt middle Elems. empty
119
- and back = Xt. exchange ~xt back Elems. empty in
146
+ let take_all ~xt q =
147
+ let front = Xt. exchange ~xt q. front Elems. empty
148
+ and back = Xt. unsafe_update ~xt q.back List_with_capacity. clear
149
+ and middle = Xt. exchange ~xt q.middle List_with_capacity. empty_unlimited in
120
150
seq_of ~front ~middle ~back
121
151
end
122
152
123
153
let is_empty q = Kcas.Xt. commit { tx = Xt. is_empty q }
124
154
let length q = Kcas.Xt. commit { tx = Xt. length q }
125
- let add x q = Loc. modify q.back @@ Elems. cons x
155
+
156
+ let try_add x q =
157
+ let lwc = Loc. update q.back (List_with_capacity. cons_safe x) in
158
+ let capacity = List_with_capacity. capacity lwc in
159
+ capacity = Int. max_int
160
+ ||
161
+ let back_length = List_with_capacity. length lwc in
162
+ back_length < List_with_capacity. limit lwc
163
+ || Kcas.Xt. commit { tx = Xt. try_add x q }
164
+
165
+ let add x q =
166
+ let lwc = Loc. update q.back (List_with_capacity. cons_safe x) in
167
+ if List_with_capacity. capacity lwc <> Int. max_int then
168
+ if List_with_capacity. length lwc = List_with_capacity. limit lwc then
169
+ Kcas.Xt. commit { tx = Xt. add x q }
170
+
126
171
let push = add
127
172
128
173
let take_opt q =
0 commit comments