rewrote Deque to be safe (no Obj anymore);

more functions in Deque, especially w.r.t. Sequence;
unit tests for Deque
This commit is contained in:
Simon Cruanes 2013-03-14 14:14:13 +01:00
parent 68dfbea2a0
commit 924fc1b970
5 changed files with 184 additions and 58 deletions

147
deque.ml
View file

@ -23,78 +23,111 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*) *)
(** Imperative deque *) (** {1 Imperative deque} *)
type 'a elt = { type 'a elt = {
content : 'a; content : 'a;
mutable prev : 'a elt; mutable prev : 'a elt;
mutable next : 'a elt; mutable next : 'a elt;
} } (** A cell holding a single element *)
and 'a t = 'a elt option ref
type 'a t = { (** The deque, a double linked list of cells *)
mutable first : 'a elt;
mutable length : int;
}
exception Empty exception Empty
let create () = { let create () = ref None
first = Obj.magic None;
length = 0;
}
let is_empty d = d.length = 0 let is_empty d =
match !d with
let length d = d.length | None -> true
| Some _ -> false
let mk_elt x =
let rec elt = {
content = x;
prev = elt;
next = elt;
} in elt
let push_front d x = let push_front d x =
let elt = mk_elt x in match !d with
(if d.length > 0 | None ->
then begin let rec elt = {
d.first.prev <- elt; content = x; prev = elt; next = elt;
let last = d.first.prev in } in
last.next <- elt; d := Some elt
elt.next <- d.first; | Some first ->
elt.prev <- last; let elt = { content = x; prev = first.prev; next=first; } in
end); first.prev.next <- elt;
d.first <- elt; first.prev <- elt;
d.length <- d.length + 1 d := Some elt
let push_back d x = let push_back d x =
let elt = mk_elt x in match !d with
(if d.length > 0 | None ->
then begin let rec elt = {
let last = d.first.prev in content = x; prev = elt; next = elt; } in
last.next <- elt; d := Some elt
d.first.prev <- elt; | Some first ->
elt.prev <- last; let elt = { content = x; next=first; prev=first.prev; } in
elt.next <- d.first; first.prev.next <- elt;
end else d.first <- elt); first.prev <- elt
d.length <- d.length + 1
let peek_front d =
match !d with
| None -> raise Empty
| Some first -> first.content
let peek_back d =
match !d with
| None -> raise Empty
| Some first -> first.prev.content
let take_back d = let take_back d =
(if d.length = 0 then raise Empty); match !d with
let elt = d.first.prev in | None -> raise Empty
let new_last = elt.prev in | Some first when first == first.prev ->
d.length <- d.length - 1; (* only one element *)
new_last.next <- d.first; d := None;
d.first.next <- new_last; first.content
elt.content | Some first ->
let elt = first.prev in
elt.prev.next <- first;
first.prev <- elt.prev; (* remove [first.prev] from list *)
elt.content
let take_front d = let take_front d =
(if d.length = 0 then raise Empty); match !d with
let elt = d.first in | None -> raise Empty
let new_first = elt.next in | Some first when first == first.prev ->
d.length <- d.length - 1; (* only one element *)
let last = d.first.prev in d := None;
new_first.prev <- last; first.content
last.next <- new_first; | Some first ->
elt.content first.prev.next <- first.next; (* remove [first] from list *)
first.next.prev <- first.prev;
d := Some first.next;
first.content
let iter f d =
match !d with
| None -> ()
| Some first ->
let rec iter elt =
f elt.content;
if elt.next != first then iter elt.next
in
iter first
let length (d : _ t) =
match !d with
| None -> 0
| Some _ ->
let r = ref 0 in
iter (fun _ -> incr r) d;
!r
let of_seq ?(deque=create ()) seq =
Sequence.iter (fun x -> push_back deque x) seq;
deque
let to_seq d = Sequence.from_iter (fun k -> iter k d)
(* naive implem of copy, for now *)
let copy d =
let d' = create () in
iter (fun x -> push_back d' x) d;
d'

View file

@ -23,22 +23,45 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*) *)
(** Imperative deque *) (** {1 Imperative deque} *)
type 'a t type 'a t
(** Contains 'a elements, queue in both ways *)
exception Empty exception Empty
val create : unit -> 'a t val create : unit -> 'a t
(** New deque *)
val is_empty : 'a t -> bool val is_empty : 'a t -> bool
(** Is the deque empty? *)
val length : 'a t -> int val length : 'a t -> int
(** Number of elements (linear) *)
val push_front : 'a t -> 'a -> unit val push_front : 'a t -> 'a -> unit
(** Push value at the front *)
val push_back : 'a t -> 'a -> unit val push_back : 'a t -> 'a -> unit
(** Push value at the back *)
val peek_front : 'a t -> 'a
(** First value, or Empty *)
val peek_back : 'a t -> 'a
(** Last value, or Empty *)
val take_back : 'a t -> 'a val take_back : 'a t -> 'a
(** Take last value, or raise Empty *)
val take_front : 'a t -> 'a val take_front : 'a t -> 'a
(** Take first value, or raise Empty *)
val iter : ('a -> unit) -> 'a t -> unit
(** Iterate on elements *)
val of_seq : ?deque:'a t -> 'a Sequence.t -> 'a t
val to_seq : 'a t -> 'a Sequence.t
val copy : 'a t -> 'a t
(** Fresh copy *)

52
tests/test_deque.ml Normal file
View file

@ -0,0 +1,52 @@
open OUnit
open Sequence.Infix
let plist l = Utils.sprintf "%a" (Sequence.pp_seq Format.pp_print_int) (Sequence.of_list l)
let pint i = string_of_int i
let test_length () =
let d = Deque.of_seq (1 -- 10) in
OUnit.assert_equal ~printer:pint 10 (Deque.length d)
let test_front () =
let d = Deque.of_seq (1 -- 10) in
let printer = pint in
OUnit.assert_equal ~printer 1 (Deque.peek_front d);
Deque.push_front d 42;
OUnit.assert_equal ~printer 42 (Deque.peek_front d);
OUnit.assert_equal ~printer 42 (Deque.take_front d);
OUnit.assert_equal ~printer 1 (Deque.take_front d);
OUnit.assert_equal ~printer 2 (Deque.take_front d);
OUnit.assert_equal ~printer 3 (Deque.take_front d);
OUnit.assert_equal ~printer 10 (Deque.peek_back d);
()
let test_back () =
let d = Deque.of_seq (1 -- 10) in
let printer = pint in
OUnit.assert_equal ~printer 1 (Deque.peek_front d);
Deque.push_back d 42;
OUnit.assert_equal ~printer 42 (Deque.peek_back d);
OUnit.assert_equal ~printer 42 (Deque.take_back d);
OUnit.assert_equal ~printer 10 (Deque.take_back d);
OUnit.assert_equal ~printer 9 (Deque.take_back d);
OUnit.assert_equal ~printer 8 (Deque.take_back d);
OUnit.assert_equal ~printer 1 (Deque.peek_front d);
()
let test_iter () =
let d = Deque.of_seq (1 -- 5) in
let s = Sequence.from_iter (fun k -> Deque.iter k d) in
let l = Sequence.to_list s in
OUnit.assert_equal ~printer:plist [1;2;3;4;5] l;
()
let suite =
"test_deque" >:::
[ "test_length" >:: test_length;
"test_front" >:: test_front;
"test_back" >:: test_back;
"test_iter" >:: test_iter;
]

View file

@ -5,6 +5,7 @@ open OUnit
let suite = let suite =
"all_tests" >::: "all_tests" >:::
[ Test_pHashtbl.suite; [ Test_pHashtbl.suite;
Test_deque.suite;
Test_fHashtbl.suite; Test_fHashtbl.suite;
Test_fQueue.suite; Test_fQueue.suite;
Test_flatHashtbl.suite; Test_flatHashtbl.suite;

17
utils.ml Normal file
View file

@ -0,0 +1,17 @@
(** {1 Some very basic utils} *)
(* val sprintf : ('a, Format.formatter, unit, string) format4 -> 'a *)
let sprintf format =
let buffer = Buffer.create 32 in
let fmt = Format.formatter_of_buffer buffer in
Format.kfprintf
(begin fun fmt ->
Format.pp_print_flush fmt ();
let s = Buffer.contents buffer in
Buffer.clear buffer;
s
end)
fmt
format