mirror of
https://github.com/c-cube/iter.git
synced 2025-12-09 12:45:36 -05:00
merge from master: version 0.5.1
This commit is contained in:
commit
e5625c6930
8 changed files with 178 additions and 28 deletions
|
|
@ -1,5 +1,10 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.5.1
|
||||||
|
|
||||||
|
- `Sequence.IO` module, a very very simple way to read/write files
|
||||||
|
- options: `to_opt/of_opt/head/head_exn`
|
||||||
|
|
||||||
## 0.5
|
## 0.5
|
||||||
|
|
||||||
- conversion with `klist`
|
- conversion with `klist`
|
||||||
|
|
|
||||||
6
META
6
META
|
|
@ -1,6 +1,6 @@
|
||||||
# OASIS_START
|
# OASIS_START
|
||||||
# DO NOT EDIT (digest: 97bacb5c6907fa4ab239010b6f052d2a)
|
# DO NOT EDIT (digest: 3b9ebef180f5e4bdb720d2103ba95667)
|
||||||
version = "0.5"
|
version = "0.5.1"
|
||||||
description = "Simple sequence (iterator) datatype and combinators"
|
description = "Simple sequence (iterator) datatype and combinators"
|
||||||
archive(byte) = "sequence.cma"
|
archive(byte) = "sequence.cma"
|
||||||
archive(byte, plugin) = "sequence.cma"
|
archive(byte, plugin) = "sequence.cma"
|
||||||
|
|
@ -8,7 +8,7 @@ archive(native) = "sequence.cmxa"
|
||||||
archive(native, plugin) = "sequence.cmxs"
|
archive(native, plugin) = "sequence.cmxs"
|
||||||
exists_if = "sequence.cma"
|
exists_if = "sequence.cma"
|
||||||
package "invert" (
|
package "invert" (
|
||||||
version = "0.5"
|
version = "0.5.1"
|
||||||
description = "Simple sequence (iterator) datatype and combinators"
|
description = "Simple sequence (iterator) datatype and combinators"
|
||||||
requires = "sequence delimcc"
|
requires = "sequence delimcc"
|
||||||
archive(byte) = "invert.cma"
|
archive(byte) = "invert.cma"
|
||||||
|
|
|
||||||
3
Makefile
3
Makefile
|
|
@ -57,10 +57,11 @@ push_stable: all
|
||||||
git push origin
|
git push origin
|
||||||
git checkout master
|
git checkout master
|
||||||
|
|
||||||
VERSION=$(shell awk '/Version:/ {print $$2}' _oasis)
|
VERSION=$(shell awk '/^Version:/ {print $$2}' _oasis)
|
||||||
|
|
||||||
update_next_tag:
|
update_next_tag:
|
||||||
@echo "update version to $(VERSION)..."
|
@echo "update version to $(VERSION)..."
|
||||||
sed -i "s/NEXT_VERSION/$(VERSION)/g" *.ml *.mli
|
sed -i "s/NEXT_VERSION/$(VERSION)/g" *.ml *.mli
|
||||||
|
sed -i "s/NEXT_RELEASE/$(VERSION)/g" *.ml *.mli
|
||||||
|
|
||||||
.PHONY: benchs tests examples update_next_tag push_doc push_stable
|
.PHONY: benchs tests examples update_next_tag push_doc push_stable
|
||||||
|
|
|
||||||
15
README.md
15
README.md
|
|
@ -12,12 +12,16 @@ way of iterating on a finite number of values, only allocating (most of the time
|
||||||
one intermediate closure to do so. For instance, iterating on keys, or values,
|
one intermediate closure to do so. For instance, iterating on keys, or values,
|
||||||
of a `Hashtbl.t`, without creating a list.
|
of a `Hashtbl.t`, without creating a list.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
=============
|
||||||
|
|
||||||
|
See [the online API](http://cedeela.fr/~simon/software/sequence/Sequence.html).
|
||||||
|
|
||||||
Build
|
Build
|
||||||
=====
|
=====
|
||||||
|
|
||||||
You need OCaml, say OCaml 3.12 or OCaml 4.0.
|
1. via opam `opam install sequence`
|
||||||
|
2. manually (need OCaml >= 3.12): `make all install`
|
||||||
$ make
|
|
||||||
|
|
||||||
If you have `OUnit` installed, you can build and run tests with
|
If you have `OUnit` installed, you can build and run tests with
|
||||||
|
|
||||||
|
|
@ -40,11 +44,6 @@ The module `examples/sexpr.mli` exposes the interface of the S-expression
|
||||||
example library. It requires OCaml>=4.0 to compile, because of the GADT
|
example library. It requires OCaml>=4.0 to compile, because of the GADT
|
||||||
structure used in the monadic parser combinators part of `examples/sexpr.ml`.
|
structure used in the monadic parser combinators part of `examples/sexpr.ml`.
|
||||||
|
|
||||||
Documentation
|
|
||||||
=============
|
|
||||||
|
|
||||||
See [the online API](http://cedeela.fr/~simon/software/sequence/Sequence.html).
|
|
||||||
|
|
||||||
License
|
License
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|
|
||||||
2
_oasis
2
_oasis
|
|
@ -1,6 +1,6 @@
|
||||||
OASISFormat: 0.4
|
OASISFormat: 0.4
|
||||||
Name: sequence
|
Name: sequence
|
||||||
Version: 0.5
|
Version: 0.5.1
|
||||||
Homepage: https://github.com/c-cube/sequence
|
Homepage: https://github.com/c-cube/sequence
|
||||||
Authors: Simon Cruanes
|
Authors: Simon Cruanes
|
||||||
License: BSD-2-clause
|
License: BSD-2-clause
|
||||||
|
|
|
||||||
70
sequence.ml
70
sequence.ml
|
|
@ -321,6 +321,17 @@ let min ?(lt=fun x y -> x < y) seq =
|
||||||
|
|
||||||
exception ExitSequence
|
exception ExitSequence
|
||||||
|
|
||||||
|
let head seq =
|
||||||
|
let r = ref None in
|
||||||
|
try
|
||||||
|
seq (fun x -> r := Some x; raise ExitSequence); None
|
||||||
|
with ExitSequence -> !r
|
||||||
|
|
||||||
|
let head_exn seq =
|
||||||
|
match head seq with
|
||||||
|
| None -> invalid_arg "Sequence.head_exn"
|
||||||
|
| Some x -> x
|
||||||
|
|
||||||
let take n seq k =
|
let take n seq k =
|
||||||
let count = ref 0 in
|
let count = ref 0 in
|
||||||
try
|
try
|
||||||
|
|
@ -425,6 +436,12 @@ let to_list seq = List.rev (fold (fun y x -> x::y) [] seq)
|
||||||
|
|
||||||
let to_rev_list seq = fold (fun y x -> x :: y) [] seq
|
let to_rev_list seq = fold (fun y x -> x :: y) [] seq
|
||||||
|
|
||||||
|
let to_opt = head
|
||||||
|
|
||||||
|
let of_opt o k = match o with
|
||||||
|
| None -> ()
|
||||||
|
| Some x -> k x
|
||||||
|
|
||||||
let of_list l k = List.iter k l
|
let of_list l k = List.iter k l
|
||||||
|
|
||||||
let to_array seq =
|
let to_array seq =
|
||||||
|
|
@ -699,3 +716,56 @@ let to_string ?sep pp_elt seq =
|
||||||
let buf = Buffer.create 25 in
|
let buf = Buffer.create 25 in
|
||||||
pp_buf ?sep (fun buf x -> Buffer.add_string buf (pp_elt x)) buf seq;
|
pp_buf ?sep (fun buf x -> Buffer.add_string buf (pp_elt x)) buf seq;
|
||||||
Buffer.contents buf
|
Buffer.contents buf
|
||||||
|
|
||||||
|
(** {2 Basic IO} *)
|
||||||
|
|
||||||
|
module IO = struct
|
||||||
|
let lines_of ?(mode=0o644) ?(flags=[Open_rdonly]) filename =
|
||||||
|
fun k ->
|
||||||
|
let ic = open_in_gen flags mode filename in
|
||||||
|
try
|
||||||
|
while true do
|
||||||
|
let line = input_line ic in
|
||||||
|
k line
|
||||||
|
done
|
||||||
|
with
|
||||||
|
| End_of_file -> close_in ic
|
||||||
|
| e -> close_in_noerr ic; raise e
|
||||||
|
|
||||||
|
let chunks_of ?(mode=0o644) ?(flags=[]) ?(size=1024) filename =
|
||||||
|
fun k ->
|
||||||
|
let ic = open_in_gen flags mode filename in
|
||||||
|
try
|
||||||
|
let buf = String.create size in
|
||||||
|
let n = ref 0 in
|
||||||
|
let stop = ref false in
|
||||||
|
while not !stop do
|
||||||
|
n := 0;
|
||||||
|
(* try to read [size] chars. If [input] returns [0] it means
|
||||||
|
the end of file, so we stop, but first we yield the current chunk *)
|
||||||
|
while !n < size && not !stop do
|
||||||
|
let n' = input ic buf !n (size - !n) in
|
||||||
|
if n' = 0 then stop := true else n := !n + n';
|
||||||
|
done;
|
||||||
|
if !n > 0
|
||||||
|
then k (String.sub buf 0 !n)
|
||||||
|
done;
|
||||||
|
close_in ic
|
||||||
|
with e ->
|
||||||
|
close_in_noerr ic;
|
||||||
|
raise e
|
||||||
|
|
||||||
|
let write_to ?(mode=0o644) ?(flags=[Open_creat;Open_wronly]) filename seq =
|
||||||
|
let oc = open_out_gen flags mode filename in
|
||||||
|
try
|
||||||
|
seq (fun s -> output oc s 0 (String.length s));
|
||||||
|
close_out oc
|
||||||
|
with e ->
|
||||||
|
close_out oc;
|
||||||
|
raise e
|
||||||
|
|
||||||
|
let write_lines ?mode ?flags filename seq =
|
||||||
|
write_to ?mode ?flags filename (snoc (intersperse "\n" seq) "\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
99
sequence.mli
99
sequence.mli
|
|
@ -23,10 +23,10 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*)
|
*)
|
||||||
|
|
||||||
(** {1 Transient iterators, that abstract on a finite sequence of elements.} *)
|
(** {1 Simple and Efficient Iterators} *)
|
||||||
|
|
||||||
(** The iterators are designed to allow easy transfer (mappings) between data
|
(** The iterators are designed to allow easy transfer (mappings) between data
|
||||||
structures, without defining n^2 conversions between the n types. The
|
structures, without defining [n^2] conversions between the [n] types. The
|
||||||
implementation relies on the assumption that a sequence can be iterated
|
implementation relies on the assumption that a sequence can be iterated
|
||||||
on as many times as needed; this choice allows for high performance
|
on as many times as needed; this choice allows for high performance
|
||||||
of many combinators. However, for transient iterators, the {!persistent}
|
of many combinators. However, for transient iterators, the {!persistent}
|
||||||
|
|
@ -53,8 +53,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
of this memory structure, cheaply and repeatably. *)
|
of this memory structure, cheaply and repeatably. *)
|
||||||
|
|
||||||
type +'a t = ('a -> unit) -> unit
|
type +'a t = ('a -> unit) -> unit
|
||||||
(** Sequence abstract iterator type, representing a finite sequence of
|
(** A sequence of values of type ['a]. If you give it a function ['a -> unit]
|
||||||
values of type ['a]. *)
|
it will be applied to every element of the sequence successively. *)
|
||||||
|
|
||||||
type +'a sequence = 'a t
|
type +'a sequence = 'a t
|
||||||
|
|
||||||
|
|
@ -97,7 +97,7 @@ val repeat : 'a -> 'a t
|
||||||
at {!take} and the likes if you iterate on it. *)
|
at {!take} and the likes if you iterate on it. *)
|
||||||
|
|
||||||
val iterate : ('a -> 'a) -> 'a -> 'a t
|
val iterate : ('a -> 'a) -> 'a -> 'a t
|
||||||
(** [iterate f x] is the infinite sequence (x, f(x), f(f(x)), ...) *)
|
(** [iterate f x] is the infinite sequence [x, f(x), f(f(x)), ...] *)
|
||||||
|
|
||||||
val forever : (unit -> 'b) -> 'b t
|
val forever : (unit -> 'b) -> 'b t
|
||||||
(** Sequence that calls the given function to produce elements.
|
(** Sequence that calls the given function to produce elements.
|
||||||
|
|
@ -113,7 +113,8 @@ val cycle : 'a t -> 'a t
|
||||||
(** {2 Consume a sequence} *)
|
(** {2 Consume a sequence} *)
|
||||||
|
|
||||||
val iter : ('a -> unit) -> 'a t -> unit
|
val iter : ('a -> unit) -> 'a t -> unit
|
||||||
(** Consume the sequence, passing all its arguments to the function *)
|
(** Consume the sequence, passing all its arguments to the function.
|
||||||
|
Basically [iter f seq] is just [seq f]. *)
|
||||||
|
|
||||||
val iteri : (int -> 'a -> unit) -> 'a t -> unit
|
val iteri : (int -> 'a -> unit) -> 'a t -> unit
|
||||||
(** Iterate on elements and their index in the sequence *)
|
(** Iterate on elements and their index in the sequence *)
|
||||||
|
|
@ -253,12 +254,23 @@ val min : ?lt:('a -> 'a -> bool) -> 'a t -> 'a option
|
||||||
(** Min element of the sequence, using the given comparison function.
|
(** Min element of the sequence, using the given comparison function.
|
||||||
see {!max} for more details. *)
|
see {!max} for more details. *)
|
||||||
|
|
||||||
|
val head : 'a t -> 'a option
|
||||||
|
(** First element, if any, otherwise [None]
|
||||||
|
@since 0.5.1 *)
|
||||||
|
|
||||||
|
val head_exn : 'a t -> 'a
|
||||||
|
(** First element, if any, fails
|
||||||
|
@raise Invalid_argument if the sequence is empty
|
||||||
|
@since 0.5.1 *)
|
||||||
|
|
||||||
val take : int -> 'a t -> 'a t
|
val take : int -> 'a t -> 'a t
|
||||||
(** Take at most [n] elements from the sequence. Works on infinite
|
(** Take at most [n] elements from the sequence. Works on infinite
|
||||||
sequences. *)
|
sequences. *)
|
||||||
|
|
||||||
val take_while : ('a -> bool) -> 'a t -> 'a t
|
val take_while : ('a -> bool) -> 'a t -> 'a t
|
||||||
(** Take elements while they satisfy the predicate, then stops iterating *)
|
(** Take elements while they satisfy the predicate, then stops iterating.
|
||||||
|
Will work on an infinite sequence [s] if the predicate is false for at
|
||||||
|
least one element of [s]. *)
|
||||||
|
|
||||||
val drop : int -> 'a t -> 'a t
|
val drop : int -> 'a t -> 'a t
|
||||||
(** Drop the [n] first elements of the sequence. Lazy. *)
|
(** Drop the [n] first elements of the sequence. Lazy. *)
|
||||||
|
|
@ -307,9 +319,13 @@ val to_rev_list : 'a t -> 'a list
|
||||||
|
|
||||||
val of_list : 'a list -> 'a t
|
val of_list : 'a list -> 'a t
|
||||||
|
|
||||||
|
val to_opt : 'a t -> 'a option
|
||||||
|
(** Alias to {!head}
|
||||||
|
@since 0.5.1 *)
|
||||||
|
|
||||||
val to_array : 'a t -> 'a array
|
val to_array : 'a t -> 'a array
|
||||||
(** Convert to an array. Currently not very efficient because
|
(** Convert to an array. Currently not very efficient because
|
||||||
and intermediate list is used. *)
|
an intermediate list is used. *)
|
||||||
|
|
||||||
val of_array : 'a array -> 'a t
|
val of_array : 'a array -> 'a t
|
||||||
|
|
||||||
|
|
@ -322,6 +338,10 @@ val array_slice : 'a array -> int -> int -> 'a t
|
||||||
(** [array_slice a i j] Sequence of elements whose indexes range
|
(** [array_slice a i j] Sequence of elements whose indexes range
|
||||||
from [i] to [j] *)
|
from [i] to [j] *)
|
||||||
|
|
||||||
|
val of_opt : 'a option -> 'a t
|
||||||
|
(** Iterate on 0 or 1 values.
|
||||||
|
@since 0.5.1 *)
|
||||||
|
|
||||||
val of_stream : 'a Stream.t -> 'a t
|
val of_stream : 'a Stream.t -> 'a t
|
||||||
(** Sequence of elements of a stream (usable only once) *)
|
(** Sequence of elements of a stream (usable only once) *)
|
||||||
|
|
||||||
|
|
@ -482,16 +502,20 @@ module Infix : sig
|
||||||
It will therefore be empty if [a < b]. *)
|
It will therefore be empty if [a < b]. *)
|
||||||
|
|
||||||
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
|
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
|
||||||
(** Monadic bind (infix version of {!flat_map} *)
|
(** Monadic bind (infix version of {!flat_map}
|
||||||
|
@since 0.5 *)
|
||||||
|
|
||||||
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
|
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
|
||||||
(** Infix version of {!map} *)
|
(** Infix version of {!map}
|
||||||
|
@since 0.5 *)
|
||||||
|
|
||||||
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
|
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
|
||||||
(** Applicative operator (product+application) *)
|
(** Applicative operator (product+application)
|
||||||
|
@since 0.5 *)
|
||||||
|
|
||||||
val (<+>) : 'a t -> 'a t -> 'a t
|
val (<+>) : 'a t -> 'a t -> 'a t
|
||||||
(** Concatenation of sequences *)
|
(** Concatenation of sequences
|
||||||
|
@since 0.5 *)
|
||||||
end
|
end
|
||||||
|
|
||||||
include module type of Infix
|
include module type of Infix
|
||||||
|
|
@ -510,3 +534,54 @@ val pp_buf : ?sep:string -> (Buffer.t -> 'a -> unit) ->
|
||||||
|
|
||||||
val to_string : ?sep:string -> ('a -> string) -> 'a t -> string
|
val to_string : ?sep:string -> ('a -> string) -> 'a t -> string
|
||||||
(** Print into a string *)
|
(** Print into a string *)
|
||||||
|
|
||||||
|
(** {2 Basic IO}
|
||||||
|
|
||||||
|
Very basic interface to manipulate files as sequence of chunks/lines. The
|
||||||
|
sequences take care of opening and closing files properly; every time
|
||||||
|
one iterates over a sequence, the file is opened/closed again.
|
||||||
|
|
||||||
|
Example: copy a file ["a"] into file ["b"], removing blank lines:
|
||||||
|
|
||||||
|
{[
|
||||||
|
Sequence.(IO.lines_of "a" |> filter (fun l-> l<> "") |> IO.write_lines "b");;
|
||||||
|
]}
|
||||||
|
|
||||||
|
By chunks of [4096] bytes:
|
||||||
|
|
||||||
|
{[
|
||||||
|
Sequence.IO.(chunks_of ~size:4096 "a" |> write_to "b");;
|
||||||
|
]}
|
||||||
|
|
||||||
|
@since 0.5.1 *)
|
||||||
|
|
||||||
|
module IO : sig
|
||||||
|
val lines_of : ?mode:int -> ?flags:open_flag list ->
|
||||||
|
string -> string t
|
||||||
|
(** [lines_of filename] reads all lines of the given file. It raises the
|
||||||
|
same exception as would opening the file and read from it, except
|
||||||
|
from [End_of_file] (which is caught). The file is {b always} properly
|
||||||
|
closed.
|
||||||
|
Every time the sequence is iterated on, the file is opened again, so
|
||||||
|
different iterations might return different results
|
||||||
|
@param mode default [0o644]
|
||||||
|
@param flags default: [[Open_rdonly]] *)
|
||||||
|
|
||||||
|
val chunks_of : ?mode:int -> ?flags:open_flag list -> ?size:int ->
|
||||||
|
string -> string t
|
||||||
|
(** Read chunks of the given [size] from the file. The last chunk might be
|
||||||
|
smaller. Behaves like {!lines_of} regarding errors and options.
|
||||||
|
Every time the sequence is iterated on, the file is opened again, so
|
||||||
|
different iterations might return different results *)
|
||||||
|
|
||||||
|
val write_to : ?mode:int -> ?flags:open_flag list ->
|
||||||
|
string -> string t -> unit
|
||||||
|
(** [write_to filename seq] writes all strings from [seq] into the given
|
||||||
|
file. It takes care of opening and closing the file.
|
||||||
|
@param mode default [0o644]
|
||||||
|
@param flags used by [open_out_gen]. Default: [[Open_creat;Open_wronly]]. *)
|
||||||
|
|
||||||
|
val write_lines : ?mode:int -> ?flags:open_flag list ->
|
||||||
|
string -> string t -> unit
|
||||||
|
(** Same as {!write_to}, but intercales ['\n'] between each string *)
|
||||||
|
end
|
||||||
|
|
|
||||||
6
setup.ml
6
setup.ml
|
|
@ -1,7 +1,7 @@
|
||||||
(* setup.ml generated for the first time by OASIS v0.4.4 *)
|
(* setup.ml generated for the first time by OASIS v0.4.4 *)
|
||||||
|
|
||||||
(* OASIS_START *)
|
(* OASIS_START *)
|
||||||
(* DO NOT EDIT (digest: 623687f8c58c30bc6ff9a8e5ebe8f593) *)
|
(* DO NOT EDIT (digest: d7a207daf3186cce7792651a50aaba59) *)
|
||||||
(*
|
(*
|
||||||
Regenerated by OASIS v0.4.4
|
Regenerated by OASIS v0.4.4
|
||||||
Visit http://oasis.forge.ocamlcore.org for more information and
|
Visit http://oasis.forge.ocamlcore.org for more information and
|
||||||
|
|
@ -6826,7 +6826,7 @@ let setup_t =
|
||||||
alpha_features = [];
|
alpha_features = [];
|
||||||
beta_features = [];
|
beta_features = [];
|
||||||
name = "sequence";
|
name = "sequence";
|
||||||
version = "0.5";
|
version = "0.5.1";
|
||||||
license =
|
license =
|
||||||
OASISLicense.DEP5License
|
OASISLicense.DEP5License
|
||||||
(OASISLicense.DEP5Unit
|
(OASISLicense.DEP5Unit
|
||||||
|
|
@ -7192,7 +7192,7 @@ let setup_t =
|
||||||
};
|
};
|
||||||
oasis_fn = Some "_oasis";
|
oasis_fn = Some "_oasis";
|
||||||
oasis_version = "0.4.4";
|
oasis_version = "0.4.4";
|
||||||
oasis_digest = Some "6\2028\169\031Z \246[\195\132\t\168\226\152(";
|
oasis_digest = Some "8\252\157\1340^<0\133GR\029nmc6";
|
||||||
oasis_exec = None;
|
oasis_exec = None;
|
||||||
oasis_setup_args = [];
|
oasis_setup_args = [];
|
||||||
setup_update = false
|
setup_update = false
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue