diff --git a/src/util/Chunk_stack.ml b/src/util/Chunk_stack.ml index eef6ff36..32bcc72a 100644 --- a/src/util/Chunk_stack.ml +++ b/src/util/Chunk_stack.ml @@ -75,10 +75,8 @@ module Reader = struct read: 'a. yield:(bytes -> int -> int -> 'a) -> finish:(unit -> 'a) -> 'a; } [@@unboxed] - let[@inline] next (self:t) f : bool = - self.read - ~yield:(fun b i len -> f b i len; true) - ~finish:(fun () -> false) + let[@inline] next (self:t) ~yield ~finish = + self.read ~yield ~finish let next_string (self:t) : string option = self.read @@ -108,14 +106,11 @@ module Reader = struct in { read; } - let with_file_backward (filename:string) f = - CCIO.with_in ~flags:[Open_binary; Open_rdonly] filename @@ fun ic -> - + let from_channel_backward ic = let len = in_channel_length ic in seek_in ic len; - let blen = Bytes.create 4 in (* to read length *) - let buf = Buf.create() in (* local buffer *) + let buf = Buf.create ~cap:32 () in (* local buffer *) let read ~yield ~finish = let pos = pos_in ic in @@ -124,21 +119,27 @@ module Reader = struct assert (pos>=4); seek_in ic (pos - 4); - really_input ic blen 0 4; - let chunk_len = Int32.to_int (Bytes.get_int32_le blen 0) in + really_input ic buf.Buf.b 0 4; + let chunk_len = Int32.to_int (Bytes.get_int32_le buf.Buf.b 0) in (* now read chunk *) Buf.ensure_size_ buf chunk_len; seek_in ic (pos - 4 - chunk_len); really_input ic buf.Buf.b 0 chunk_len; buf.Buf.len <- chunk_len; + seek_in ic (pos - 4 - chunk_len); yield buf.Buf.b 0 buf.Buf.len ) else ( finish() ) in - f {read} + {read} + + let with_file_backward (filename:string) f = + CCIO.with_in ~flags:[Open_binary; Open_rdonly] filename @@ fun ic -> + let r = from_channel_backward ic in + f r end (*$T diff --git a/src/util/Chunk_stack.mli b/src/util/Chunk_stack.mli index 3ee6ab6b..86e3785d 100644 --- a/src/util/Chunk_stack.mli +++ b/src/util/Chunk_stack.mli @@ -46,9 +46,8 @@ end module Reader : sig type t - val next : t -> (bytes -> int -> int -> unit) -> bool - (** Read next chunk, call the function with a slice of bytes. - Returns [true] if a chunk was read, [false] if no more chunks are there. *) + val next : t -> yield:(bytes -> int -> int -> 'a) -> finish:(unit -> 'a) -> 'a + (** Read next chunk, call [yield] with a slice of bytes, otherwise call [finish()]. *) val next_string : t -> string option (** Read next chunk as a string *) @@ -57,9 +56,12 @@ module Reader : sig val from_buf : Buf.t -> t + val from_channel_backward : in_channel -> t + (** Read channel from the end, assuming that is possible. *) + + val with_file_backward : string -> (t -> 'a) -> 'a (** [read_file_backward filename f] calls [f] with an iterator over chunks of the file, read from the end. Each chunk is assumed to be followed by its length as an int32 LE. *) - val with_file_backward : string -> (t -> 'a) -> 'a end