package base
Source file 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 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 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558open! Import (* [t] stores the [t.length] queue elements at consecutive increasing indices of [t.elts], mod the capacity of [t], which is [Option_array.length t.elts]. The capacity is required to be a power of two (user-requested capacities are rounded up to the nearest power), so that mod can quickly be computed using [land t.mask], where [t.mask = capacity t - 1]. So, queue element [i] is at [t.elts.( (t.front + i) land t.mask )]. [num_mutations] is used to detect modification during iteration. *) type 'a t = { mutable num_mutations : int ; mutable front : int ; mutable mask : int ; mutable length : int ; mutable elts : 'a Option_array.t } [@@deriving_inline sexp_of] let sexp_of_t : 'a. ('a -> Sexplib0.Sexp.t) -> 'a t -> Sexplib0.Sexp.t = fun _of_a__001_ { num_mutations = num_mutations__003_ ; front = front__005_ ; mask = mask__007_ ; length = length__009_ ; elts = elts__011_ } -> let bnds__002_ = ([] : _ Stdlib.List.t) in let bnds__002_ = let arg__012_ = Option_array.sexp_of_t _of_a__001_ elts__011_ in (Sexplib0.Sexp.List [ Sexplib0.Sexp.Atom "elts"; arg__012_ ] :: bnds__002_ : _ Stdlib.List.t) in let bnds__002_ = let arg__010_ = sexp_of_int length__009_ in (Sexplib0.Sexp.List [ Sexplib0.Sexp.Atom "length"; arg__010_ ] :: bnds__002_ : _ Stdlib.List.t) in let bnds__002_ = let arg__008_ = sexp_of_int mask__007_ in (Sexplib0.Sexp.List [ Sexplib0.Sexp.Atom "mask"; arg__008_ ] :: bnds__002_ : _ Stdlib.List.t) in let bnds__002_ = let arg__006_ = sexp_of_int front__005_ in (Sexplib0.Sexp.List [ Sexplib0.Sexp.Atom "front"; arg__006_ ] :: bnds__002_ : _ Stdlib.List.t) in let bnds__002_ = let arg__004_ = sexp_of_int num_mutations__003_ in (Sexplib0.Sexp.List [ Sexplib0.Sexp.Atom "num_mutations"; arg__004_ ] :: bnds__002_ : _ Stdlib.List.t) in Sexplib0.Sexp.List bnds__002_ ;; [@@@end] let globalize _ t = { num_mutations = t.num_mutations ; front = t.front ; mask = t.mask ; length = t.length ; elts = Option_array.copy t.elts } ;; module type S = Queue_intf.S let inc_num_mutations t = t.num_mutations <- t.num_mutations + 1 let capacity t = t.mask + 1 let elts_index t i = (t.front + i) land t.mask let unsafe_get t i = Option_array.unsafe_get_some_exn t.elts (elts_index t i) let unsafe_is_set t i = Option_array.unsafe_is_some t.elts (elts_index t i) let unsafe_set t i a = Option_array.unsafe_set_some t.elts (elts_index t i) a let unsafe_unset t i = Option_array.unsafe_set_none t.elts (elts_index t i) let check_index_exn t i = if i < 0 || i >= t.length then Error.raise_s (Sexp.message "Queue index out of bounds" [ "index", i |> Int.sexp_of_t; "length", t.length |> Int.sexp_of_t ]) ;; let get t i = check_index_exn t i; unsafe_get t i ;; let set t i a = check_index_exn t i; inc_num_mutations t; unsafe_set t i a ;; let is_empty t = t.length = 0 let length { length; _ } = length let[@cold] [@inline never] raise_mutation_during_iteration t = Error.raise_s (Sexp.message "mutation of queue during iteration" [ "", t |> globalize () |> sexp_of_t (fun _ -> Sexp.Atom "_") ]) ;; let ensure_no_mutation t num_mutations = if t.num_mutations <> num_mutations then raise_mutation_during_iteration t ;; let compare__local = let rec unsafe_compare_from compare_elt pos ~t1 ~t2 ~len1 ~len2 ~mut1 ~mut2 = match pos = len1, pos = len2 with | true, true -> 0 | true, false -> -1 | false, true -> 1 | false, false -> let x = compare_elt (unsafe_get t1 pos) (unsafe_get t2 pos) in ensure_no_mutation t1 mut1; ensure_no_mutation t2 mut2; (match x with | 0 -> unsafe_compare_from compare_elt (pos + 1) ~t1 ~t2 ~len1 ~len2 ~mut1 ~mut2 | n -> n) in fun compare_elt t1 t2 -> if phys_equal t1 t2 then 0 else unsafe_compare_from compare_elt 0 ~t1 ~t2 ~len1:t1.length ~len2:t2.length ~mut1:t1.num_mutations ~mut2:t2.num_mutations ;; let compare compare_elt t1 t2 = compare__local compare_elt t1 t2 let equal__local = let rec unsafe_equal_from equal_elt pos ~t1 ~t2 ~mut1 ~mut2 ~len = pos = len || let b = equal_elt (unsafe_get t1 pos) (unsafe_get t2 pos) in ensure_no_mutation t1 mut1; ensure_no_mutation t2 mut2; b && unsafe_equal_from equal_elt (pos + 1) ~t1 ~t2 ~mut1 ~mut2 ~len in fun equal_elt t1 t2 -> phys_equal t1 t2 || let len1 = t1.length in let len2 = t2.length in len1 = len2 && unsafe_equal_from equal_elt 0 ~t1 ~t2 ~len:len1 ~mut1:t1.num_mutations ~mut2:t2.num_mutations ;; let equal equal_elt t1 t2 = equal__local equal_elt t1 t2 let invariant invariant_a t = let { num_mutations; mask = _; elts; front; length } = t in assert (front >= 0); assert (front < capacity t); let capacity = capacity t in assert (capacity = Option_array.length elts); assert (capacity >= 1); assert (Int.is_pow2 capacity); assert (length >= 0); assert (length <= capacity); for i = 0 to capacity - 1 do if i < t.length then ( invariant_a (unsafe_get t i); ensure_no_mutation t num_mutations) else assert (not (unsafe_is_set t i)) done ;; let create (type a) ?capacity () : a t = let capacity = match capacity with | None -> 2 | Some capacity -> if capacity < 0 then Error.raise_s (Sexp.message "cannot have queue with negative capacity" [ "capacity", capacity |> Int.sexp_of_t ]) else if capacity = 0 then 1 else Int.ceil_pow2 capacity in { num_mutations = 0 ; front = 0 ; mask = capacity - 1 ; length = 0 ; elts = Option_array.create ~len:capacity } ;; let blit_to_array ~src dst = assert (src.length <= Option_array.length dst); let front_len = Int.min src.length (capacity src - src.front) in let rest_len = src.length - front_len in Option_array.blit ~len:front_len ~src:src.elts ~src_pos:src.front ~dst ~dst_pos:0; Option_array.blit ~len:rest_len ~src:src.elts ~src_pos:0 ~dst ~dst_pos:front_len ;; let set_capacity_internal t new_capacity = let dst = Option_array.create ~len:new_capacity in blit_to_array ~src:t dst; t.front <- 0; t.mask <- new_capacity - 1; t.elts <- dst ;; let set_capacity t desired_capacity = (* We allow arguments less than 1 to [set_capacity], but translate them to 1 to simplify the code that relies on the array length being a power of 2. *) inc_num_mutations t; let new_capacity = Int.ceil_pow2 (max 1 (max desired_capacity t.length)) in if new_capacity <> capacity t then set_capacity_internal t new_capacity ;; let enqueue t a = inc_num_mutations t; if t.length = capacity t then set_capacity_internal t (2 * t.length); unsafe_set t t.length a; t.length <- t.length + 1 ;; let enqueue_front t a = inc_num_mutations t; if t.length = capacity t then set_capacity_internal t (2 * t.length); let front = (t.front - 1) land t.mask in t.front <- front; t.length <- t.length + 1; unsafe_set t 0 a ;; let dequeue_nonempty t = inc_num_mutations t; let elts = t.elts in let front = t.front in let res = Option_array.get_some_exn elts front in Option_array.set_none elts front; t.front <- elts_index t 1; t.length <- t.length - 1; res ;; let back_index t = elts_index t (t.length - 1) let dequeue_back_nonempty t = inc_num_mutations t; let elts = t.elts in let back = back_index t in let res = Option_array.get_some_exn elts back in Option_array.set_none elts back; t.length <- t.length - 1; res ;; let dequeue_exn t = if is_empty t then raise Stdlib.Queue.Empty else dequeue_nonempty t let dequeue t = if is_empty t then None else Some (dequeue_nonempty t) let dequeue_and_ignore_exn (type elt) (t : elt t) = ignore (dequeue_exn t : elt) let dequeue_back_exn t = if is_empty t then raise Stdlib.Queue.Empty else dequeue_back_nonempty t ;; let dequeue_back t = if is_empty t then None else Some (dequeue_back_nonempty t) let front_nonempty t = Option_array.unsafe_get_some_exn t.elts t.front let back_nonempty t = Option_array.unsafe_get_some_exn t.elts (back_index t) let last_nonempty t = unsafe_get t (t.length - 1) let peek t = if is_empty t then None else Some (front_nonempty t) let peek_exn t = if is_empty t then raise Stdlib.Queue.Empty else front_nonempty t let peek_back t = if is_empty t then None else Some (back_nonempty t) let peek_back_exn t = if is_empty t then raise Stdlib.Queue.Empty else back_nonempty t let last t = if is_empty t then None else Some (last_nonempty t) let last_exn t = if is_empty t then raise Stdlib.Queue.Empty else last_nonempty t let drain t ~f ~while_ = while (not (is_empty t)) && while_ (front_nonempty t) do f (dequeue_nonempty t) done ;; let clear t = inc_num_mutations t; if t.length > 0 then ( for i = 0 to t.length - 1 do unsafe_unset t i done; t.length <- 0; t.front <- 0) ;; let blit_transfer ~src ~dst ?len () = inc_num_mutations src; inc_num_mutations dst; let len = match len with | None -> src.length | Some len -> if len < 0 then Error.raise_s (Sexp.message "Queue.blit_transfer: negative length" [ "length", len |> Int.sexp_of_t ]); min len src.length in if len > 0 then ( set_capacity dst (max (capacity dst) (dst.length + len)); let dst_start = dst.front + dst.length in for i = 0 to len - 1 do (* This is significantly faster than simply [enqueue dst (dequeue_nonempty src)] *) let src_i = (src.front + i) land src.mask in let dst_i = (dst_start + i) land dst.mask in Option_array.unsafe_set_some dst.elts dst_i (Option_array.unsafe_get_some_exn src.elts src_i); Option_array.unsafe_set_none src.elts src_i done; dst.length <- dst.length + len; src.front <- (src.front + len) land src.mask; src.length <- src.length - len) ;; let enqueue_all t l = (* Traversing the list up front to compute its length is probably (but not definitely) better than doubling the underlying array size several times for large queues. *) set_capacity t (Int.max (capacity t) (t.length + List.length l)); List.iter l ~f:(fun x -> enqueue t x) ;; let fold t ~init ~f = if t.length = 0 then init else ( let num_mutations = t.num_mutations in let r = ref init in for i = 0 to t.length - 1 do r := f !r (unsafe_get t i); ensure_no_mutation t num_mutations done; !r) ;; let foldi t ~init ~f = let i = ref 0 in fold t ~init ~f:(fun acc a -> let acc = f !i acc a in i := !i + 1; acc) [@nontail] ;; (* [iter] is implemented directly because implementing it in terms of [fold] is slower. *) let iter t ~f = let num_mutations = t.num_mutations in for i = 0 to t.length - 1 do f (unsafe_get t i); ensure_no_mutation t num_mutations done ;; let iteri t ~f = let num_mutations = t.num_mutations in for i = 0 to t.length - 1 do f i (unsafe_get t i); ensure_no_mutation t num_mutations done ;; let to_list t = let result = ref [] in for i = t.length - 1 downto 0 do result := unsafe_get t i :: !result done; !result ;; module C = Indexed_container.Make (struct type nonrec 'a t = 'a t let fold = fold let iter = `Custom iter let length = `Custom length let foldi = `Custom foldi let iteri = `Custom iteri end) let count = C.count let exists = C.exists let find = C.find let find_map = C.find_map let fold_result = C.fold_result let fold_until = C.fold_until let for_all = C.for_all let max_elt = C.max_elt let mem = C.mem let min_elt = C.min_elt let sum = C.sum let counti = C.counti let existsi = C.existsi let find_mapi = C.find_mapi let findi = C.findi let for_alli = C.for_alli (* For [concat_map], [filter_map], and [filter], we don't create [t_result] with [t]'s capacity because we have no idea how many elements [t_result] will ultimately hold. *) let concat_map t ~f = let t_result = create () in iter t ~f:(fun a -> List.iter (f a) ~f:(fun b -> enqueue t_result b)); t_result ;; let concat_mapi t ~f = let t_result = create () in iteri t ~f:(fun i a -> List.iter (f i a) ~f:(fun b -> enqueue t_result b)); t_result ;; let filter_map t ~f = let t_result = create () in iter t ~f:(fun a -> match f a with | None -> () | Some b -> enqueue t_result b); t_result ;; let filter_mapi t ~f = let t_result = create () in iteri t ~f:(fun i a -> match f i a with | None -> () | Some b -> enqueue t_result b); t_result ;; let filter t ~f = let t_result = create () in iter t ~f:(fun a -> if f a then enqueue t_result a); t_result ;; let filteri t ~f = let t_result = create () in iteri t ~f:(fun i a -> if f i a then enqueue t_result a); t_result ;; let filter_inplace t ~f = let t2 = filter t ~f in clear t; blit_transfer ~src:t2 ~dst:t () ;; let filteri_inplace t ~f = let t2 = filteri t ~f in clear t; blit_transfer ~src:t2 ~dst:t () ;; let copy src = let dst = create ~capacity:src.length () in blit_to_array ~src dst.elts; dst.length <- src.length; dst ;; let of_list l = (* Traversing the list up front to compute its length is probably (but not definitely) better than doubling the underlying array size several times for large queues. *) let t = create ~capacity:(List.length l) () in List.iter l ~f:(fun x -> enqueue t x); t ;; (* The queue [t] returned by [create] will have [t.length = 0], [t.front = 0], and [capacity t = Int.ceil_pow2 len]. So, we only have to set [t.length] to [len] after the blit to maintain all the invariants: [t.length] is equal to the number of elements in the queue, [t.front] is the array index of the first element in the queue, and [capacity t = Option_array.length t.elts]. *) let init len ~f = if len < 0 then Error.raise_s (Sexp.message "Queue.init: negative length" [ "length", len |> Int.sexp_of_t ]); let t = create ~capacity:len () in assert (Option_array.length t.elts >= len); for i = 0 to len - 1 do Option_array.unsafe_set_some t.elts i (f i) done; t.length <- len; t ;; let of_array a = init (Array.length a) ~f:(Array.unsafe_get a) let to_array t = Array.init t.length ~f:(fun i -> unsafe_get t i) let map ta ~f = let num_mutations = ta.num_mutations in let tb = create ~capacity:ta.length () in tb.length <- ta.length; for i = 0 to ta.length - 1 do let b = f (unsafe_get ta i) in ensure_no_mutation ta num_mutations; Option_array.unsafe_set_some tb.elts i b done; tb ;; let mapi t ~f = let i = ref 0 in map t ~f:(fun a -> let result = f !i a in i := !i + 1; result) [@nontail] ;; let singleton x = let t = create ~capacity:1 () in enqueue t x; t ;; let sexp_of_t sexp_of_a t = to_list t |> List.sexp_of_t sexp_of_a let t_of_sexp a_of_sexp sexp = List.t_of_sexp a_of_sexp sexp |> of_list let t_sexp_grammar (type a) (grammar : a Sexplib0.Sexp_grammar.t) : a t Sexplib0.Sexp_grammar.t = Sexplib0.Sexp_grammar.coerce (List.t_sexp_grammar grammar) ;; module Iteration = struct type t = int let start q = q.num_mutations let assert_no_mutation_since_start t q = ensure_no_mutation q t end