module Stream : sig
type 'a t
- val lines : in_channel -> string t
- val rec_file_paths : root:string -> string t
+
+ val create : (unit -> 'a option) -> 'a t
+
val iter : 'a t -> f:('a -> unit) -> unit
end = struct
module S = Stream
type 'a t =
'a S.t
- let rec_file_paths ~root =
+ let create f =
+ S.from (fun _ -> f ())
+
+ let iter t ~f =
+ S.iter f t
+end
+
+module In_channel : sig
+ val lines : in_channel -> string Stream.t
+end = struct
+ let lines ic =
+ Stream.create (fun () ->
+ match input_line ic with
+ | exception End_of_file ->
+ None
+ | line ->
+ Some line
+ )
+end
+
+module Directory_tree : sig
+ val find_files : string -> string Stream.t
+end = struct
+ let find_files root =
let dirs = Queue.create () in
let files = Queue.create () in
- Queue.add root dirs;
let explore parent =
Array.iter (Sys.readdir parent) ~f:(fun child ->
let path = Filename.concat parent child in
()
)
in
- let next_dir () =
- match Queue.take dirs with
- | exception Queue.Empty ->
- ()
- | dir ->
- explore dir
- in
- let next_file () =
- match Queue.take files with
- | exception Queue.Empty ->
- None
- | file_path ->
- Some file_path
+ explore root;
+ let rec next () =
+ match Queue.is_empty files, Queue.is_empty dirs with
+ | false, _ -> Some (Queue.take files)
+ | true , true -> None
+ | true , false ->
+ explore (Queue.take dirs);
+ next ()
in
- S.from (fun _ ->
- next_dir ();
- next_file ()
- )
-
- let lines ic =
- S.from (fun _ ->
- match input_line ic with
- | exception End_of_file ->
- None
- | line ->
- Some line
- )
-
- let iter t ~f =
- S.iter f t
+ Stream.create next
end
type input =
let main input =
let paths =
match input with
- | Paths_on_stdin -> Stream.lines stdin
- | Root_path root -> Stream.rec_file_paths ~root
+ | Paths_on_stdin -> In_channel.lines stdin
+ | Root_path root -> Directory_tree.find_files root
in
let paths_by_digest = Hashtbl.create 1_000_000 in
let path_count = ref 0 in
let () =
let input = ref Paths_on_stdin in
- Arg.parse [] (fun path -> input := Root_path path) "";
+ Arg.parse
+ []
+ (function
+ | path when Sys.file_exists path ->
+ input := Root_path path
+ | path ->
+ eprintf "File does not exist: %S\n%!" path;
+ exit 1
+ )
+ "";
main !input