Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
dllist.ml1 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 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269open Kcas (** Tagged GADT for representing doubly-linked lists. The [lhs] and [rhs] fields are the first two fields in both a [List] and a [Node] so that it is possible (by using an unsafe cast) to access the fields without knowing whether the target is a [List] or a [Node]. *) type ('a, _) tdt = | List : { lhs : 'a cursor Loc.t; (** [lhs] points to the rightmost node of this list or to the list itself in case the list is empty. *) rhs : 'a cursor Loc.t; (** [rhs] points to the leftmost node of this list or to the list itself in case the list is empty. *) } -> ('a, [> `List ]) tdt | Node : { lhs : 'a cursor Loc.t; (** [lhs] points to the node on the left side of this node, to the list if this node is the leftmost node, or to the node itself in case this node is not in any list. *) rhs : 'a cursor Loc.t; (** [rhs] points to the node on the right side of this node, to the list if this node is the rightmost node, or to the node itself in case this node is not in any list. *) value : 'a; } -> ('a, [> `Node ]) tdt and 'a cursor = At : ('a, [< `List | `Node ]) tdt -> 'a cursor [@@unboxed] type 'a t = ('a, [ `List ]) tdt type 'a node = ('a, [ `Node ]) tdt external as_list : ('a, _) tdt -> 'a t = "%identity" external as_node : ('a, _) tdt -> 'a node = "%identity" let[@inline] get (Node { value; _ } : 'a node) = value let[@inline] lhs_of list_or_node = let (List list_r) = as_list list_or_node in list_r.lhs let[@inline] rhs_of list_or_node = let (List list_r) = as_list list_or_node in list_r.rhs let[@inline] value_of (Node node_r : 'a node) = node_r.value let create () = let lhs = Loc.make ~padded:true (Obj.magic ()) in let rhs = Loc.make ~padded:true (Obj.magic ()) in let list = Multicore_magic.copy_as_padded (List { lhs; rhs }) in Loc.set lhs (At list); Loc.set rhs (At list); list let create_node value = let node = let lhs = Loc.make (Obj.magic ()) in let rhs = Loc.make (Obj.magic ()) in Node { lhs; rhs; value } in Loc.set (lhs_of node) (At node); Loc.set (rhs_of node) (At node); node let create_node_with ~lhs ~rhs value = Node { lhs = Loc.make (At lhs); rhs = Loc.make (At rhs); value } module Xt = struct let remove ~xt node = let (At rhs) = Xt.exchange ~xt (rhs_of node) (At node) in if At rhs != At node then begin let (At lhs) = Xt.exchange ~xt (lhs_of node) (At node) in Xt.set ~xt (lhs_of rhs) (At lhs); Xt.set ~xt (rhs_of lhs) (At rhs) end let is_empty ~xt list = Xt.get ~xt (lhs_of list) == At list let add_node_l ~xt node list = let (At rhs) = Xt.get ~xt (rhs_of list) in assert (Loc.fenceless_get (lhs_of node) == At list); Loc.set (rhs_of node) (At rhs); Xt.set ~xt (rhs_of list) (At node); Xt.set ~xt (lhs_of rhs) (At node); node let add_l ~xt value list = let (At rhs) = Xt.get ~xt (rhs_of list) in let node = create_node_with ~lhs:list ~rhs value in Xt.set ~xt (rhs_of list) (At node); Xt.set ~xt (lhs_of rhs) (At node); node let add_node_r ~xt node list = let (At lhs) = Xt.get ~xt (lhs_of list) in Loc.set (lhs_of node) (At lhs); assert (Loc.fenceless_get (rhs_of node) == At list); Xt.set ~xt (lhs_of list) (At node); Xt.set ~xt (rhs_of lhs) (At node); node let add_r ~xt value list = let (At lhs) = Xt.get ~xt (lhs_of list) in let node = create_node_with ~lhs ~rhs:list value in Xt.set ~xt (lhs_of list) (At node); Xt.set ~xt (rhs_of lhs) (At node); node let move_l ~xt node list = let (At list_rhs) = Xt.exchange ~xt (rhs_of list) (At node) in if At list_rhs != At node then begin let (At node_lhs) = Xt.exchange ~xt (lhs_of node) (At list) in let (At node_rhs) = Xt.exchange ~xt (rhs_of node) (At list_rhs) in if At node_lhs != At node then begin Xt.set ~xt (rhs_of node_lhs) (At node_rhs); Xt.set ~xt (lhs_of node_rhs) (At node_lhs) end; Xt.set ~xt (lhs_of list_rhs) (At node) end let move_r ~xt node list = let (At list_lhs) = Xt.exchange ~xt (lhs_of list) (At node) in if At list_lhs != At node then begin let (At node_rhs) = Xt.exchange ~xt (rhs_of node) (At list) in let (At node_lhs) = Xt.exchange ~xt (lhs_of node) (At list_lhs) in if At node_rhs != At node then begin Xt.set ~xt (rhs_of node_lhs) (At node_rhs); Xt.set ~xt (lhs_of node_rhs) (At node_lhs) end; Xt.set ~xt (rhs_of list_lhs) (At node) end let take_opt_l ~xt list = let (At rhs) = Xt.get ~xt (rhs_of list) in if At rhs == At list then None else let node = as_node rhs in remove ~xt node; Some (value_of node) let take_opt_r ~xt list = let (At lhs) = Xt.get ~xt (lhs_of list) in if At lhs == At list then None else let node = as_node lhs in remove ~xt node; Some (value_of node) let take_blocking_l ~xt list = Xt.to_blocking ~xt (take_opt_l list) let take_blocking_r ~xt list = Xt.to_blocking ~xt (take_opt_r list) let transfer_l ~xt t1 t2 = let (At t1_rhs) = Xt.exchange ~xt (rhs_of t1) (At t1) in if At t1_rhs != At t1 then begin let (At t1_lhs) = Xt.exchange ~xt (lhs_of t1) (At t1) in let (At t2_rhs) = Xt.exchange ~xt (rhs_of t2) (At t1_rhs) in Xt.set ~xt (lhs_of t2_rhs) (At t1_lhs); Xt.set ~xt (lhs_of t1_rhs) (At t2); Xt.set ~xt (rhs_of t1_lhs) (At t2_rhs) end let transfer_r ~xt t1 t2 = let (At t1_rhs) = Xt.exchange ~xt (rhs_of t1) (At t1) in if At t1_rhs != At t1 then begin let (At t1_lhs) = Xt.exchange ~xt (lhs_of t1) (At t1) in let (At t2_lhs) = Xt.exchange ~xt (lhs_of t2) (At t1_lhs) in Xt.set ~xt (rhs_of t2_lhs) (At t1_rhs); Xt.set ~xt (rhs_of t1_lhs) (At t2); Xt.set ~xt (lhs_of t1_rhs) (At t2_lhs) end let swap ~xt t1 t2 = let (At t1_rhs) = Xt.get ~xt (rhs_of t1) in if At t1_rhs == At t1 then transfer_l ~xt t2 t1 else let (At t2_lhs) = Xt.get ~xt (lhs_of t2) in if At t2_lhs == At t2 then transfer_l ~xt t1 t2 else let (At t1_lhs) = Xt.exchange ~xt (lhs_of t1) (At t2_lhs) in let (At t2_rhs) = Xt.exchange ~xt (rhs_of t2) (At t1_rhs) in Xt.set ~xt (lhs_of t2) (At t1_lhs); Xt.set ~xt (rhs_of t1) (At t2_rhs); Xt.set ~xt (lhs_of t2_rhs) (At t1); Xt.set ~xt (rhs_of t2_lhs) (At t1); Xt.set ~xt (lhs_of t1_rhs) (At t2); Xt.set ~xt (rhs_of t1_lhs) (At t2) let[@tail_mod_cons] rec to_list_as_l ~xt f list (At at) = if At at == At list then [] else f (as_node at) :: to_list_as_l ~xt f list (Xt.get ~xt (rhs_of at)) let to_list_as_l ~xt f list = to_list_as_l ~xt f list (Xt.get ~xt (rhs_of list)) let to_list_l ~xt list = to_list_as_l ~xt get list let to_nodes_l ~xt list = to_list_as_l ~xt Fun.id list let[@tail_mod_cons] rec to_list_as_r ~xt f list (At at) = if At at == At list then [] else f (as_node at) :: to_list_as_r ~xt f list (Xt.get ~xt (lhs_of at)) let to_list_as_r ~xt f list = to_list_as_r ~xt f list (Xt.get ~xt (lhs_of list)) let to_list_r ~xt list = to_list_as_r ~xt get list let to_nodes_r ~xt list = to_list_as_r ~xt Fun.id list end let remove node = Kcas.Xt.commit { tx = Xt.remove node } let is_empty list = Loc.get (lhs_of list) == At list let add_l value list = let node = create_node_with ~lhs:list ~rhs:list value in Kcas.Xt.commit { tx = Xt.add_node_l node list } let add_r value list = let node = create_node_with ~lhs:list ~rhs:list value in Kcas.Xt.commit { tx = Xt.add_node_r node list } let move_l node list = Kcas.Xt.commit { tx = Xt.move_l node list } let move_r node list = Kcas.Xt.commit { tx = Xt.move_r node list } let take_opt_l list = Kcas.Xt.commit { tx = Xt.take_opt_l list } let take_opt_r list = Kcas.Xt.commit { tx = Xt.take_opt_r list } let take_blocking_l ?timeoutf list = Kcas.Xt.commit ?timeoutf { tx = Xt.take_blocking_l list } let take_blocking_r ?timeoutf list = Kcas.Xt.commit ?timeoutf { tx = Xt.take_blocking_r list } let swap t1 t2 = Kcas.Xt.commit { tx = Xt.swap t1 t2 } let transfer_l t1 t2 = Kcas.Xt.commit { tx = Xt.transfer_l t1 t2 } let transfer_r t1 t2 = Kcas.Xt.commit { tx = Xt.transfer_r t1 t2 } let to_list_l list = Kcas.Xt.commit { tx = Xt.to_list_l list } let to_list_r list = Kcas.Xt.commit { tx = Xt.to_list_r list } let to_nodes_l list = Kcas.Xt.commit { tx = Xt.to_nodes_l list } let to_nodes_r list = Kcas.Xt.commit { tx = Xt.to_nodes_r list } exception Empty let take_l list = match take_opt_l list with None -> raise Empty | Some v -> v let take_r list = match take_opt_r list with None -> raise Empty | Some v -> v let take_all list = let copy = let lhs = Loc.make ~padded:true (At list) in let rhs = Loc.make ~padded:true (At list) in List { lhs; rhs } |> Multicore_magic.copy_as_padded in let open Kcas in let tx ~xt = let (At lhs) = Xt.exchange ~xt (lhs_of list) (At list) in if At lhs == At list then begin Loc.set (lhs_of copy) (At copy); Loc.set (rhs_of copy) (At copy) end else let (At rhs) = Xt.exchange ~xt (rhs_of list) (At list) in Xt.set ~xt (rhs_of lhs) (At copy); Xt.set ~xt (lhs_of rhs) (At copy); Loc.set (lhs_of copy) (At lhs); Loc.set (rhs_of copy) (At rhs) in Xt.commit { tx }; copy