URLエンコード(ocaml)

急にocamlのコードを書いてみたくなったので、以前に他言語用に書いたURLエンコードのソースをocamlに翻訳した。
以下、成果物のメモ。

(* file: url_encode.ml *)

(* Read whole file *)
(* refer: http://www.ocaml-tutorial.org/ja/if_statements,_loops_and_recursion *)
let read_whole_chan chan = 
  let len = in_channel_length chan in
  let result = String.create len in
    really_input chan result 0 len;
    result ;;

let read_whole_file filename =
  let chan = open_in filename in
    read_whole_chan chan ;;

(* URL encode *)
let is_safe_char c = 
  match c with
      '0'..'9' | 'a'..'z' | 'A'..'Z' | '.' | '-' | '_' | '*' -> true
    | _ -> false ;;

let encode_char_to_hex c buf =
  String.set buf 1 "0123456789ABCDEF".[(int_of_char c land 0xF0) lsr 4];
  String.set buf 2 "0123456789ABCDEF".[int_of_char c land 0x0F];
  buf ;;

let url_encode s =
  let hexbuf = "%__" in
  let dist = Buffer.create 1024 in
  let conv c =
    if is_safe_char c then Buffer.add_char dist c
    else if c=' '     then Buffer.add_char dist '+'
    else                   Buffer.add_string dist (encode_char_to_hex c hexbuf) in
    String.iter conv s;
    Buffer.contents dist ;;

(* main *)
let s = read_whole_file Sys.argv.(1) in
  url_encode s;;

コンパイルと計時。

# 処理速度を重視するコンパイラオプションとかはあるのか?
$ ocamlopt url_encode.ml -o url_encode

# 夏目漱石の『こころ』(UTF-8,542KB)をエンコード
$ time url_encode /path/to/kokoro
real	0m0.053s
user	0m0.052s
sys	0m0.000s

速度的に悪くはないけど、他の言語で作成したものよりは遅い(C++: 0.025s, sbcl: 0.032s)
多分(上のコードよりも)もっと効率的に文字列を操作する方法があるんだろうな。