ocaml-containers/src/data/CCDeque.ml
2024-05-13 20:57:53 -04:00

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 "}@]"