ocaml-containers/src/data/CCDeque.ml
2017-01-25 00:08:12 +01:00

415 lines
9.5 KiB
OCaml

(* This file is free software, part of containers. See file "license" for more details. *)
(** {1 Imperative deque} *)
type 'a cell =
| Zero
| One of 'a
| Two of 'a * 'a
| Three of 'a * 'a * 'a
(** A cell holding a small number of elements *)
type 'a node = {
mutable cell : 'a cell;
mutable next : 'a node;
mutable prev : 'a 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 *)
(*$inject
let plist l = CCFormat.(to_string (list int)) l
let pint i = string_of_int i
*)
(*$R
let q = create () in
add_seq_back q Sequence.(3 -- 5);
assert_equal [3;4;5] (to_list q);
add_seq_front q Sequence.(of_list [2;1]);
assert_equal [1;2;3;4;5] (to_list q);
push_front q 0;
assert_equal [0;1;2;3;4;5] (to_list q);
assert_equal 5 (take_back q);
assert_equal 0 (take_front q);
assert_equal 4 (length q);
*)
exception Empty
let create () =
let rec cur = { cell=Zero; prev=cur; next=cur } in
{ cur; size=0 }
let clear q =
let rec cur = { cell=Zero; prev=cur; next=cur } in
q.cur <- cur;
q.size <- 0;
()
(*$R
let q = of_seq Sequence.(1 -- 100) in
assert_equal 100 (length q);
clear q;
assert_equal 0 (length q);
assert_raises Empty (fun () -> peek_front q);
assert_raises Empty (fun () -> peek_back q);
*)
let incr_size_ d = d.size <- d.size + 1
let decr_size_ d = d.size <- d.size - 1
let is_zero_ n = match n.cell with
| Zero -> true
| One _
| Two _
| Three _ -> false
let is_empty d =
let res = d.size = 0 in
assert (res = is_zero_ d.cur);
res
let push_front d x =
incr_size_ d;
match d.cur.cell with
| Zero -> d.cur.cell <- One x
| One y -> d.cur.cell <- Two (x, y)
| Two (y, z) -> d.cur.cell <- Three (x,y,z)
| Three _ ->
let node = { cell = One x; prev = d.cur.prev; next=d.cur; } in
d.cur.prev.next <- node;
d.cur.prev <- node;
d.cur <- node (* always point to first node *)
let push_back d x =
incr_size_ d;
let n = d.cur.prev in (* last node *)
match n.cell with
| Zero -> n.cell <- One x
| One y -> n.cell <- Two (y, x)
| Two (y,z) -> n.cell <- Three (y, z, x)
| Three _ ->
let elt = { cell = One x; next=d.cur; prev=n; } in
n.next <- elt;
d.cur.prev <- elt
let peek_front d = match d.cur.cell with
| Zero -> raise Empty
| One x -> x
| Two (x,_) -> x
| Three (x,_,_) -> x
(*$T
of_list [1;2;3] |> peek_front = 1
try (ignore (of_list [] |> peek_front); false) with Empty -> true
*)
(*$R
let d = of_seq Sequence.(1 -- 10) in
let printer = pint in
OUnit.assert_equal ~printer 1 (peek_front d);
push_front d 42;
OUnit.assert_equal ~printer 42 (peek_front d);
OUnit.assert_equal ~printer 42 (take_front d);
OUnit.assert_equal ~printer 1 (take_front d);
OUnit.assert_equal ~printer 2 (take_front d);
OUnit.assert_equal ~printer 3 (take_front d);
OUnit.assert_equal ~printer 10 (peek_back d);
*)
let peek_back d =
if is_empty d then raise Empty
else match d.cur.prev.cell with
| Zero -> assert false
| One x -> x
| Two (_,x) -> x
| Three (_,_,x) -> x
(*$T
of_list [1;2;3] |> peek_back = 3
try (ignore (of_list [] |> peek_back); false) with Empty -> true
*)
(*$R
let d = of_seq Sequence.(1 -- 10) in
let printer = pint in
OUnit.assert_equal ~printer 1 (peek_front d);
push_back d 42;
OUnit.assert_equal ~printer 42 (peek_back d);
OUnit.assert_equal ~printer 42 (take_back d);
OUnit.assert_equal ~printer 10 (take_back d);
OUnit.assert_equal ~printer 9 (take_back d);
OUnit.assert_equal ~printer 8 (take_back d);
OUnit.assert_equal ~printer 1 (peek_front d);
*)
let take_back_node_ n = match n.cell with
| Zero -> assert false
| One x -> n.cell <- Zero; x
| Two (x,y) -> n.cell <- One x; y
| Three (x,y,z) -> n.cell <- Two (x,y); z
let take_back d =
if is_empty d then raise Empty
else if d.cur == d.cur.prev
then (
(* only one cell *)
decr_size_ d;
take_back_node_ d.cur
) else (
let n = d.cur.prev in
let x = take_back_node_ n in
decr_size_ d;
if is_zero_ n
then ( (* remove previous node *)
d.cur.prev <- n.prev;
n.prev.next <- d.cur;
);
x
)
(*$T
let q = of_list [1;2;3] in take_back q = 3 && to_list q = [1;2]
*)
let take_front_node_ n = match n.cell with
| Zero -> assert false
| One x -> n.cell <- Zero; x
| Two (x,y) -> n.cell <- One y; x
| Three (x,y,z) -> n.cell <- Two (y,z); x
(*$T
let q = of_list [1;2;3] in take_front q = 1 && to_list q = [2;3]
*)
let take_front d =
if is_empty d then raise Empty
else if d.cur.prev == d.cur
then (
(* only one cell *)
decr_size_ d;
take_front_node_ d.cur
) else (
decr_size_ d;
let x = take_front_node_ d.cur in
if is_zero_ d.cur then (
d.cur.prev.next <- d.cur.next;
d.cur.next.prev <- d.cur.prev;
d.cur <- d.cur.next;
);
x
)
let iter f d =
let rec iter f ~first n =
begin match n.cell with
| Zero -> ()
| One x -> f x
| Two (x,y) -> f x; f y
| Three (x,y,z) -> f x; f y; f z
end;
if n.next != first then iter f ~first n.next
in
iter f ~first:d.cur d.cur
(*$T
let n = ref 0 in iter (fun _ -> incr n) (of_list [1;2;3]); !n = 3
*)
(*$R
let d = of_seq Sequence.(1 -- 5) in
let s = Sequence.from_iter (fun k -> iter k d) in
let l = Sequence.to_list s in
OUnit.assert_equal ~printer:plist [1;2;3;4;5] l;
*)
let append_front ~into q = iter (push_front into) q
let append_back ~into q = iter (push_back into) q
(*$R
let q = of_list [3;4] in
append_front ~into:q (of_list [2;1]);
assert_equal [1;2;3;4] (to_list q);
append_back ~into:q (of_list [5;6]);
assert_equal [1;2;3;4;5;6] (to_list q);
*)
let fold f acc d =
let rec aux ~first f acc n =
let acc = match n.cell with
| Zero -> acc
| 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 n.next == first then acc else aux ~first f acc n.next
in
aux ~first:d.cur f acc d.cur
(*$T
fold (+) 0 (of_list [1;2;3]) = 6
fold (fun acc x -> x::acc) [] (of_list [1;2;3]) = [3;2;1]
*)
let length d = d.size
(*$Q
Q.(list int) (fun l -> \
let q = of_list l in \
append_front ~into:q (of_list l); \
append_back ~into:q (of_list l); \
length q = 3 * List.length l)
*)
(*$R
let d = of_seq Sequence.(1 -- 10) in
OUnit.assert_equal ~printer:pint 10 (length d)
*)
type 'a sequence = ('a -> unit) -> unit
type 'a gen = unit -> 'a option
let add_seq_back q seq = seq (fun x -> push_back q x)
let add_seq_front q seq = seq (fun x -> push_front q x)
(*$R
let q = of_list [4;5] in
add_seq_front q Sequence.(of_list [3;2;1]);
assert_equal [1;2;3;4;5] (to_list q);
add_seq_back q Sequence.(of_list [6;7]);
assert_equal [1;2;3;4;5;6;7] (to_list q);
*)
let of_seq seq =
let deque = create () in
seq (fun x -> push_back deque x);
deque
let to_seq d k = iter k d
(*$Q
Q.(list int) (fun l -> \
Sequence.of_list l |> of_seq |> to_seq |> Sequence.to_list = l)
*)
let of_list l =
let q = create() in
List.iter (push_back q) l;
q
(*$R
let q = of_list [1;2;3] in
assert_equal 1 (take_front q);
assert_equal 3 (take_back q);
assert_equal 2 (take_front q);
assert_equal true (is_empty q)
*)
let to_rev_list q = fold (fun l x -> x::l) [] q
let to_list q = List.rev (to_rev_list 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 =
let first = q.cur in
let cell = ref q.cur.cell in
let cur = ref q.cur in
let rec next () = match !cell with
| Zero when (!cur).next == first -> None
| Zero ->
(* go to next node *)
let n = !cur in
cur := n.next;
cell := n.next.cell;
next ()
| One x -> cell := Zero; Some x
| Two (x,y) -> cell := One y; Some x
| Three (x,y,z) -> cell := Two (y,z); Some x
in
next
(*$T
of_list [1;2;3] |> to_gen |> of_gen |> to_list = [1;2;3]
*)
(*$Q
Q.(list int) (fun l -> \
of_list l |> to_gen |> of_gen |> to_list = l)
*)
(* naive implem of copy, for now *)
let copy d =
let d' = create () in
iter (fun x -> push_back d' x) d;
d'
(*$R
let q = of_list [1;2;3;4] in
assert_equal 4 (length q);
let q' = copy q in
let cmp = equal ?eq:None in
assert_equal 4 (length q');
assert_equal ~cmp q q';
push_front q 0;
assert_bool "not equal" (not (cmp q q'));
assert_equal 5 (length q);
push_front q' 0;
assert_equal ~cmp q q'
*)
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=Pervasives.compare) 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)
(*$Q
Q.(pair (list int) (list int)) (fun (l1,l2) -> \
CCOrd.equiv (compare (of_list l1) (of_list l2)) \
(CCList.compare Pervasives.compare l1 l2))
*)
type 'a printer = Format.formatter -> 'a -> unit
let print 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 "}@]"