exception Finally of exn

(* infix function composition *)
let (&) f g x = f (g x)

let time n thunk =
  let time' thunk =
    let t = Sys.time () in
      ignore (thunk ());
      Sys.time () -. t
  in
  let rec loop n i thunk =
    if i = 0
    then 0.0
    else begin
      Gc.full_major (); Gc.compact ();
      time' thunk +. (loop n (i-1) thunk)
    end
  in
    (loop (float n) n thunk) /. (float n)

(* python's try ... finally .. *)
let finalize body final =
  try
    begin
      try
	let result = body () in
	  begin
	    final ();
	    result
	  end
      with exc ->
	raise (Finally exc)
    end
  with Finally exc ->
    begin
      final ();
      raise exc
    end

let with_open_in_file ?(isstdin=(fun f -> f = "-" || f = "")) f filename =
  let chan = if isstdin filename then stdin else open_in filename in
    finalize (
      fun () ->
	f chan
    ) (
      fun () ->
	close_in chan
    )

let with_open_out_file ?(isstdout=(fun f -> f = "-" || f = "")) f filename =
  let chan = if isstdout filename then stdout else open_out filename in
    finalize (
      fun () ->
	f chan
    ) (
      fun () ->
	close_out chan
    )

let clone ?(bufsize=32 * 1024) inp out =
  let buf = String.create bufsize in
  let rec clone' () =
    let len = input inp buf 0 bufsize in
      if len = 0
      then () (* eof *)
      else begin
	output out buf 0 len;
	clone' ()
      end
  in 
    finalize (
      fun () ->
	clone' ()
    ) (
      fun () ->
	close_out out
    )

let tmpstdin ?(isstdin=(fun f -> f = "-" || f = "")) argv =
  let me = Filename.basename Sys.argv.(0) in
  let prefix =
    try
      Filename.chop_extension me
    with Invalid_argument _ ->
      me
  in
  let rec cloneit isstdin cloned tmpfile = function
      | [] -> tmpfile
      | f::rest when isstdin f ->
	  if not cloned then
	    begin
	      let tmpfile, out = (Filename.open_temp_file prefix "") in
		clone stdin out;
		at_exit (fun () -> Sys.remove tmpfile);
		cloneit isstdin true tmpfile rest
	    end
	  else
	    cloneit isstdin false "" rest
      | _::rest -> cloneit isstdin cloned "" rest
  in
  let rec fixit isstdin tmpfile = function
    | [] -> []
    | f::rest when isstdin f -> tmpfile::fixit isstdin tmpfile rest
    | f::rest -> f::fixit isstdin tmpfile rest
  in
    fixit isstdin (cloneit isstdin false "" argv) argv

(* tail-recursive *)
let explode str =
  let rec explode' n str acc =
    if n < 0
    then acc
    else explode' (n-1) str (str.[n]::acc)
  in
    explode' ((String.length str)-1) str []

(* tail-recursive *)
let implode l =
  let res = String.create (List.length l) in
  let rec imp i = function
    | [] -> res
    | c :: l -> res.[i] <- c; imp (i + 1) l in
    imp 0 l

(* tail-recursive *)
let rec dropwhile f = function
  | [] -> []
  | hd::tl when f hd -> dropwhile f tl
  | list -> list

(* NOT tail-recursive *)
let readlines chan =
  let rec readlines' chan lines =
    try
      readlines' chan ((input_line chan)::lines)
    with End_of_file ->
      List.rev lines
  in
    readlines' chan []

let rec getline chan =			(* non-exceptional version of input_line *)
  try 
    Some (input_line chan)
  with End_of_file ->
    None

(* tail-recursive *)
let rec maplines f chan =
  let rec maplines' f chan acc =
    match getline chan with
      | Some line -> maplines' f chan ((f line)::acc)
      | None      -> List.rev acc
  in maplines' f chan []

(* tail-recursive *)
let rec iterlines f chan =
  match getline chan with
    | Some line -> f line; iterlines f chan
    | None      -> ()

(* transpose a list of lists *)
(* tail-recursive *)
let transpose ll =
  let rec transpose' acc = function
    | [] -> acc
    | []::_ -> acc
    | m -> transpose' ((List.map List.hd m)::acc) (List.map List.tl m)
  in
    List.rev (transpose' [] ll)

(* NOT tail-recursive *)
(*
 * let rec join c str =
 *     match str with
 *       []           -> ""
 *     | [x]          -> x
 *     | (x1::x2::xs) -> x1 ^ c ^ join c (x2::xs)
 *)

(* convert a string list into a string by separating elements with string c *)
(* HOLY CRAP!  String.concat already does this!! *)
(* tail-recursive *)
let join str list =
  let rec join' acc str = function
    | []           -> acc
    | [x]          -> acc ^ str ^ x
    | (x1::x2::xs) -> join' (acc ^ str ^ x1) str (x2::xs)
  in
  let result = (join' "" str list) in
    if result = ""
    then ""
    else String.sub result (String.length str) (String.length result - (String.length str))

module Cset = Set.Make(struct type t = char let compare = compare end)

let split ?(tr=true) ?(merge=false) cs str =
  let rec split1 cs str =
    let len = String.length str in
    let chars = explode cs in
    let cset = List.fold_left (fun a b -> Cset.add b a) Cset.empty (explode " \t\n") in
    let index c = try String.index str c with Not_found -> -1 in
    let indices = List.sort compare (List.filter (fun i -> i > -1) (List.map index chars)) in
    let rec findlast n =
      if n+1 < len then
	if Cset.mem str.[n+1] cset then
	  findlast (n+1)
	else n
      else n
    in
      if indices = []
      then false, str, ""
      else
	let first = List.hd indices in
	let last = if merge then findlast first else first in
	  true, String.sub str 0 first, String.sub str (last+1) (len - (last+1))
  and split'ntr cs str =		(* NOT tail-recursive *)
    match split1 cs str with
      | true,first,rest -> first::(split'ntr cs rest)
      | false,only,_    -> [only]
  and split'tr cs str =			(* tail-recursive *)
    let rec split' cs str acc =
      match split1 cs str with
	| true,first,rest -> split' cs rest (first::acc)
	| false,only,_    -> only::acc
    in
      List.rev (split' cs str [])
  in
    (if tr then split'tr else split'ntr) cs str

(* 10 times faster than: implode (dropwhile ((=) cs) (explode str)) *)
(* not recursive *)
let rec trimleft cs str =
  if str = "" then
    ""
  else
    let i = ref 0 in
    let n = ref (String.length str) in
      while str.[!i] = cs do
	i := !i + 1;
	n := !n - 1;
      done;
      let result = String.create !n in
	String.blit str !i result 0 !n;
	result

(* 30 times as fast as: implode (List.rev (dropwhile ((=) cs) (List.rev (explode str)))) *)
(* not recursive *)
let rec trimright cs str =
  if str = "" then
    ""
  else
    let i = ref ((String.length str) - 1) in
    let n = ref (String.length str) in
      while str.[!i] = cs do
	i := !i - 1;
	n := !n - 1;
      done;
      let result = String.create !n in
	String.blit str 0 result 0 (!i+1);
	result

(* return last element of list; more efficient than nth when you don't
   know the length of the list *)
(* tail-recursive *)
let rec last = function
  |    [] -> raise (Failure "last")
  |   [x] -> x
  | x::xs -> last xs
      
(* not recursive *)
let basename file =
  let comps = split "/" file in
    last comps

This document was generated using caml2html