mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2026-01-21 08:46:41 -05:00
489 lines
11 KiB
OCaml
489 lines
11 KiB
OCaml
(* This file is free software, part of containers. See file "license" for more details. *)
|
|
|
|
(** {1 Imperative deque} *)
|
|
|
|
type 'a cell =
|
|
| One of 'a
|
|
| Two of 'a * 'a
|
|
| Three of 'a * 'a * 'a (** A cell holding a small number of elements *)
|
|
|
|
type 'a inner_node = {
|
|
mutable cell: 'a cell;
|
|
mutable next: 'a inner_node;
|
|
mutable prev: 'a inner_node;
|
|
}
|
|
|
|
type 'a node =
|
|
| Empty
|
|
| Node of 'a inner_node
|
|
(** Linked list of cells.
|
|
|
|
invariant: only the first and last cells are allowed to
|
|
be anything but [Three] (all the intermediate ones are [Three])
|
|
*)
|
|
|
|
type 'a t = {
|
|
mutable cur: 'a node;
|
|
mutable size: int;
|
|
}
|
|
(** The deque, a double linked list of cells *)
|
|
|
|
exception Empty
|
|
|
|
let create () = { cur = Empty; size = 0 }
|
|
|
|
let clear q =
|
|
q.cur <- Empty;
|
|
q.size <- 0;
|
|
()
|
|
|
|
let incr_size_ d = d.size <- d.size + 1
|
|
let decr_size_ d = d.size <- d.size - 1
|
|
let bool_eq (a : bool) b = Stdlib.( = ) a b
|
|
|
|
let is_empty d =
|
|
let res = d.size = 0 in
|
|
assert (bool_eq res (d.cur = Empty));
|
|
res
|
|
|
|
let push_front d x =
|
|
incr_size_ d;
|
|
match d.cur with
|
|
| Empty ->
|
|
let rec node = { cell = One x; prev = node; next = node } in
|
|
d.cur <- Node node
|
|
| Node n ->
|
|
(match n.cell with
|
|
| One y -> n.cell <- Two (x, y)
|
|
| Two (y, z) -> n.cell <- Three (x, y, z)
|
|
| Three _ ->
|
|
let node = { cell = One x; prev = n.prev; next = n } in
|
|
n.prev.next <- node;
|
|
n.prev <- node;
|
|
d.cur <- Node node
|
|
(* always point to first node *))
|
|
|
|
let push_back d x =
|
|
incr_size_ d;
|
|
match d.cur with
|
|
| Empty ->
|
|
let rec node = { cell = One x; prev = node; next = node } in
|
|
d.cur <- Node node
|
|
| Node cur ->
|
|
let n = cur.prev in
|
|
(* last node *)
|
|
(match n.cell with
|
|
| One y -> n.cell <- Two (y, x)
|
|
| Two (y, z) -> n.cell <- Three (y, z, x)
|
|
| Three _ ->
|
|
let elt = { cell = One x; next = cur; prev = n } in
|
|
n.next <- elt;
|
|
cur.prev <- elt)
|
|
|
|
let peek_front_opt d =
|
|
match d.cur with
|
|
| Empty -> None
|
|
| Node cur ->
|
|
(match cur.cell with
|
|
| One x -> Some x
|
|
| Two (x, _) -> Some x
|
|
| Three (x, _, _) -> Some x)
|
|
|
|
let peek_front d =
|
|
match peek_front_opt d with
|
|
| None -> raise Empty
|
|
| Some x -> x
|
|
|
|
let peek_back_opt d =
|
|
match d.cur with
|
|
| Empty -> None
|
|
| Node cur ->
|
|
(match cur.prev.cell with
|
|
| One x -> Some x
|
|
| Two (_, x) -> Some x
|
|
| Three (_, _, x) -> Some x)
|
|
|
|
let peek_back d =
|
|
match peek_back_opt d with
|
|
| None -> raise Empty
|
|
| Some x -> x
|
|
|
|
let take_back_node_ n =
|
|
match n.cell with
|
|
| One x -> true, x
|
|
| Two (x, y) ->
|
|
n.cell <- One x;
|
|
false, y
|
|
| Three (x, y, z) ->
|
|
n.cell <- Two (x, y);
|
|
false, z
|
|
|
|
let remove_node_ n =
|
|
let next = n.next in
|
|
n.prev.next <- next;
|
|
next.prev <- n.prev
|
|
|
|
let take_back_opt d =
|
|
match d.cur with
|
|
| Empty -> None
|
|
| Node cur ->
|
|
if Stdlib.( == ) cur cur.prev then (
|
|
(* only one cell *)
|
|
decr_size_ d;
|
|
let is_zero, x = take_back_node_ cur in
|
|
if is_zero then d.cur <- Empty;
|
|
Some x
|
|
) else (
|
|
let n = cur.prev in
|
|
let is_zero, x = take_back_node_ n in
|
|
decr_size_ d;
|
|
(* remove previous node *)
|
|
if is_zero then remove_node_ n;
|
|
Some x
|
|
)
|
|
|
|
let take_back d =
|
|
match take_back_opt d with
|
|
| None -> raise Empty
|
|
| Some x -> x
|
|
|
|
let take_front_node_ n =
|
|
match n.cell with
|
|
| One x -> true, x
|
|
| Two (x, y) ->
|
|
n.cell <- One y;
|
|
false, x
|
|
| Three (x, y, z) ->
|
|
n.cell <- Two (y, z);
|
|
false, x
|
|
|
|
let take_front_opt d =
|
|
match d.cur with
|
|
| Empty -> None
|
|
| Node cur ->
|
|
if Stdlib.( == ) cur.prev cur then (
|
|
(* only one cell *)
|
|
decr_size_ d;
|
|
let is_zero, x = take_front_node_ cur in
|
|
if is_zero then d.cur <- Empty;
|
|
Some x
|
|
) else (
|
|
decr_size_ d;
|
|
let is_zero, x = take_front_node_ cur in
|
|
if is_zero then (
|
|
cur.prev.next <- cur.next;
|
|
cur.next.prev <- cur.prev;
|
|
d.cur <- Node cur.next
|
|
);
|
|
Some x
|
|
)
|
|
|
|
let take_front d =
|
|
match take_front_opt d with
|
|
| None -> raise Empty
|
|
| Some x -> x
|
|
|
|
let remove_back d = ignore (take_back_opt d)
|
|
let remove_front d = ignore (take_front_opt d)
|
|
|
|
let update_front d f =
|
|
match d.cur with
|
|
| Empty -> ()
|
|
| Node cur ->
|
|
(match cur.cell with
|
|
| One x ->
|
|
(match f x with
|
|
| None ->
|
|
if Stdlib.( != ) cur.prev cur then (
|
|
cur.prev.next <- cur.next;
|
|
cur.next.prev <- cur.prev;
|
|
d.cur <- Node cur.next
|
|
) else
|
|
d.cur <- Empty
|
|
| Some x -> cur.cell <- One x)
|
|
| Two (x, y) ->
|
|
(match f x with
|
|
| None -> cur.cell <- One y
|
|
| Some x -> cur.cell <- Two (x, y))
|
|
| Three (x, y, z) ->
|
|
(match f x with
|
|
| None -> cur.cell <- Two (y, z)
|
|
| Some x -> cur.cell <- Three (x, y, z)))
|
|
|
|
let update_back d f =
|
|
match d.cur with
|
|
| Empty -> ()
|
|
| Node cur ->
|
|
let n = cur.prev in
|
|
(match n.cell with
|
|
| One x ->
|
|
(match f x with
|
|
| None ->
|
|
if Stdlib.( != ) cur.prev cur then
|
|
remove_node_ n
|
|
else
|
|
d.cur <- Empty
|
|
| Some x -> n.cell <- One x)
|
|
| Two (x, y) ->
|
|
(match f y with
|
|
| None -> n.cell <- One x
|
|
| Some y -> n.cell <- Two (x, y))
|
|
| Three (x, y, z) ->
|
|
(match f z with
|
|
| None -> n.cell <- Two (x, y)
|
|
| Some z -> n.cell <- Three (x, y, z)))
|
|
|
|
let iter f d =
|
|
let rec iter f ~first n =
|
|
(match n.cell with
|
|
| One x -> f x
|
|
| Two (x, y) ->
|
|
f x;
|
|
f y
|
|
| Three (x, y, z) ->
|
|
f x;
|
|
f y;
|
|
f z);
|
|
if n.next != first then iter f ~first n.next
|
|
in
|
|
match d.cur with
|
|
| Empty -> ()
|
|
| Node cur -> iter f ~first:cur cur
|
|
|
|
let append_front ~into q = iter (push_front into) q
|
|
let append_back ~into q = iter (push_back into) q
|
|
|
|
let fold f acc d =
|
|
let rec aux ~first f acc n =
|
|
let acc =
|
|
match n.cell with
|
|
| One x -> f acc x
|
|
| Two (x, y) -> f (f acc x) y
|
|
| Three (x, y, z) -> f (f (f acc x) y) z
|
|
in
|
|
if Stdlib.( == ) n.next first then
|
|
acc
|
|
else
|
|
aux ~first f acc n.next
|
|
in
|
|
match d.cur with
|
|
| Empty -> acc
|
|
| Node cur -> aux ~first:cur f acc cur
|
|
|
|
let length d = d.size
|
|
|
|
type 'a iter = ('a -> unit) -> unit
|
|
type 'a gen = unit -> 'a option
|
|
|
|
let add_iter_back q seq = seq (fun x -> push_back q x)
|
|
let add_iter_front q seq = seq (fun x -> push_front q x)
|
|
|
|
let of_iter seq =
|
|
let deque = create () in
|
|
seq (fun x -> push_back deque x);
|
|
deque
|
|
|
|
let to_iter d k = iter k d
|
|
|
|
let of_list l =
|
|
let q = create () in
|
|
List.iter (push_back q) l;
|
|
q
|
|
|
|
let to_rev_list q = fold (fun l x -> x :: l) [] q
|
|
let to_list q = List.rev (to_rev_list q)
|
|
|
|
let size_cell_ = function
|
|
| One _ -> 1
|
|
| Two _ -> 2
|
|
| Three _ -> 3
|
|
|
|
(* filter over a cell *)
|
|
let filter_cell_ f = function
|
|
| One x as c ->
|
|
if f x then
|
|
Some c
|
|
else
|
|
None
|
|
| Two (x, y) as c ->
|
|
let fx = f x in
|
|
let fy = f y in
|
|
(match fx, fy with
|
|
| true, true -> Some c
|
|
| true, false -> Some (One x)
|
|
| false, true -> Some (One y)
|
|
| _ -> None)
|
|
| Three (x, y, z) as c ->
|
|
let fx = f x in
|
|
let fy = f y in
|
|
let fz = f z in
|
|
(match fx, fy, fz with
|
|
| true, true, true -> Some c
|
|
| true, true, false -> Some (Two (x, y))
|
|
| true, false, true -> Some (Two (x, z))
|
|
| true, false, false -> Some (One x)
|
|
| false, true, true -> Some (Two (y, z))
|
|
| false, true, false -> Some (One y)
|
|
| false, false, true -> Some (One z)
|
|
| false, false, false -> None)
|
|
|
|
let filter_in_place (d : _ t) f : unit =
|
|
(* update size, compute new cell *)
|
|
let update_local_ n =
|
|
d.size <- d.size - size_cell_ n.cell;
|
|
match filter_cell_ f n.cell with
|
|
| None -> None
|
|
| Some n as new_cell ->
|
|
d.size <- d.size + size_cell_ n;
|
|
new_cell
|
|
in
|
|
let rec loop ~stop_at n : unit =
|
|
if n != stop_at then (
|
|
let n_prev = n.prev in
|
|
let n_next = n.next in
|
|
let new_cell = update_local_ n in
|
|
(* merge into previous cell *)
|
|
(match n_prev.cell, new_cell with
|
|
| _, None -> remove_node_ n
|
|
| Three _, Some new_cell -> n.cell <- new_cell
|
|
| One x, Some (One y) ->
|
|
remove_node_ n;
|
|
n_prev.cell <- Two (x, y)
|
|
| One x, Some (Two (y, z)) | Two (x, y), Some (One z) ->
|
|
remove_node_ n;
|
|
n_prev.cell <- Three (x, y, z)
|
|
| One x, Some (Three (y, z, w)) | Two (x, y), Some (Two (z, w)) ->
|
|
n_prev.cell <- Three (x, y, z);
|
|
n.cell <- One w
|
|
| Two (x, y), Some (Three (z, w1, w2)) ->
|
|
n_prev.cell <- Three (x, y, z);
|
|
n.cell <- Two (w1, w2));
|
|
loop ~stop_at n_next
|
|
)
|
|
in
|
|
let rec new_first_cell ~stop_at n =
|
|
if n != stop_at then (
|
|
match update_local_ n with
|
|
| None -> new_first_cell ~stop_at n.next
|
|
| Some c ->
|
|
n.cell <- c;
|
|
Some n
|
|
) else
|
|
None
|
|
in
|
|
match d.cur with
|
|
| Empty -> ()
|
|
| Node cur ->
|
|
(* special case for first cell *)
|
|
(match update_local_ cur with
|
|
| None ->
|
|
(match new_first_cell ~stop_at:cur cur.next with
|
|
| None -> d.cur <- Empty
|
|
| Some n ->
|
|
cur.prev.next <- n;
|
|
n.prev <- cur.prev;
|
|
d.cur <- Node n;
|
|
loop ~stop_at:n n.next)
|
|
| Some c ->
|
|
cur.cell <- c;
|
|
loop ~stop_at:cur cur.next)
|
|
|
|
let filter f q =
|
|
let q' = create () in
|
|
iter (fun x -> if f x then push_back q' x) q;
|
|
q'
|
|
|
|
let filter_map f q =
|
|
let q' = create () in
|
|
iter
|
|
(fun x ->
|
|
match f x with
|
|
| None -> ()
|
|
| Some y -> push_back q' y)
|
|
q;
|
|
q'
|
|
|
|
let rec gen_iter_ f g =
|
|
match g () with
|
|
| None -> ()
|
|
| Some x ->
|
|
f x;
|
|
gen_iter_ f g
|
|
|
|
let of_gen g =
|
|
let q = create () in
|
|
gen_iter_ (fun x -> push_back q x) g;
|
|
q
|
|
|
|
let to_gen q =
|
|
match q.cur with
|
|
| Empty -> fun () -> None
|
|
| Node cur ->
|
|
let first = cur in
|
|
let cell = ref (Some cur.cell) in
|
|
let cur = ref cur in
|
|
let rec next () =
|
|
match !cell with
|
|
| None when Stdlib.( == ) !cur.next first -> None
|
|
| None ->
|
|
(* go to next node *)
|
|
let n = !cur in
|
|
cur := n.next;
|
|
cell := Some n.next.cell;
|
|
next ()
|
|
| Some (One x) ->
|
|
cell := None;
|
|
Some x
|
|
| Some (Two (x, y)) ->
|
|
cell := Some (One y);
|
|
Some x
|
|
| Some (Three (x, y, z)) ->
|
|
cell := Some (Two (y, z));
|
|
Some x
|
|
in
|
|
next
|
|
|
|
(* naive implem of copy, for now *)
|
|
let copy d =
|
|
let d' = create () in
|
|
iter (fun x -> push_back d' x) d;
|
|
d'
|
|
|
|
let equal ~eq a b =
|
|
let rec aux eq a b =
|
|
match a (), b () with
|
|
| None, None -> true
|
|
| None, Some _ | Some _, None -> false
|
|
| Some x, Some y -> eq x y && aux eq a b
|
|
in
|
|
aux eq (to_gen a) (to_gen b)
|
|
|
|
let compare ~cmp a b =
|
|
let rec aux cmp a b =
|
|
match a (), b () with
|
|
| None, None -> 0
|
|
| None, Some _ -> -1
|
|
| Some _, None -> 1
|
|
| Some x, Some y ->
|
|
let c = cmp x y in
|
|
if c = 0 then
|
|
aux cmp a b
|
|
else
|
|
c
|
|
in
|
|
aux cmp (to_gen a) (to_gen b)
|
|
|
|
type 'a printer = Format.formatter -> 'a -> unit
|
|
|
|
let pp pp_x out d =
|
|
let first = ref true in
|
|
Format.fprintf out "@[<hov2>deque {";
|
|
iter
|
|
(fun x ->
|
|
if !first then
|
|
first := false
|
|
else
|
|
Format.fprintf out ";@ ";
|
|
pp_x out x)
|
|
d;
|
|
Format.fprintf out "}@]"
|