(* * $Id: lists.ocaml,v 1.9 2001/01/31 02:12:48 doug Exp $ * http://www.bagley.org/~doug/shootout/ * from Benedict Rosenau *) module Deque: sig type 'a t exception Empty val make: int -> 'a -> 'a t val iota: int -> int t val is_empty: 'a t -> bool val equal: 'a t -> 'a t -> bool val length: 'a t -> int val nth: 'a t -> int -> 'a val push_front: 'a -> 'a t -> unit val push_back: 'a t -> 'a -> unit val take_front: 'a t -> 'a val take_back: 'a t -> 'a val copy: 'a t -> 'a t val reverse: 'a t -> 'a t end = struct type 'a t = {mutable size: int; mutable first: int; mutable last: int; mutable field: 'a array; fill: 'a} exception Empty let make n dummy = let n = max n 0 in let nplus = max 1 n in {size = nplus; first = nplus lsr 1; last = (nplus lsr 1) - 1; field = Array.make nplus dummy; fill = dummy} let iota i = let i = max 0 i in let iplus = max 1 i in {size = iplus; first = 0; last = i - 1; field = Array.init iplus (fun n -> n + 1); fill = i} let length buf = buf.last - buf.first + 1 let is_empty buf = buf.last < buf.first let rec array_eq arr1 off1 arr2 off2 = function | 0 -> true | n -> if arr1.(off1) <> arr2.(off2) then false else array_eq arr1 (off1 + 1) arr2 (off2 + 1) (n - 1) let equal buf1 buf2 = let len = length buf1 in if len <> length buf2 then false else array_eq buf1.field buf1.first buf2.field buf2.first len let nth buf n = if n < 0 or n >= length buf then failwith "nth"; buf.field.(buf.first + n) let double_shift buf = let new_size = buf.size lsl 1 and len = length buf in let new_first = (new_size - len) lsr 1 and new_field = Array.make new_size buf.fill in Array.blit buf.field buf.first new_field new_first len; buf.size <- new_size; buf.field <- new_field; buf.first <- new_first; buf.last <- new_first + len - 1 let push_front elem buf = if buf.first = 0 then double_shift buf; let new_first = buf.first - 1 in buf.field.(new_first) <- elem; buf.first <- new_first let push_back buf elem = if buf.last = buf.size - 1 then double_shift buf; let new_last = buf.last + 1 in buf.field.(new_last) <- elem; buf.last <- new_last let take_front buf = if is_empty buf then raise Empty; let old_first = buf.first in buf.first <- old_first + 1; buf.field.(old_first) let take_back buf = if is_empty buf then raise Empty; let old_last = buf.last in buf.last <- old_last - 1; buf.field.(old_last) let copy buf = let len = length buf in let new_buf = make len buf.fill in Array.blit buf.field buf.first new_buf.field 0 len; new_buf.first <- 0; new_buf.last <- len - 1; new_buf let reverse buf = let len = length buf and fst = buf.first and fld = buf.field in let new_buf = make len buf.fill in let new_fld = new_buf.field in for i = 0 to len - 1 do new_fld.(len - i - 1) <- fld.(fst + i) done; new_buf.first <- 0; new_buf.last <- len - 1; new_buf end open Deque let empty () = iota 0 let size = 10000 let test_lists () = let d1 = iota size in let d2 = copy d1 and d3 = empty () in for i = 1 to length d2 do push_back d3 (take_front d2) done; for i = 1 to length d3 do push_back d2 (take_back d3) done; let d1 = reverse d1 in if size <> nth d1 0 then failwith "First test failed"; if length d1 <> length d2 then failwith "Second test failed"; if not (equal d1 d2) then failwith "Third test failed"; length d1 let _ = let n = try int_of_string Sys.argv.(1) with Invalid_argument _ -> 1 and result = ref 0 in for i = 1 to n do result := test_lists () done; Printf.printf "%d\n" !result