merge from master: version 0.5.1

This commit is contained in:
Simon Cruanes 2014-08-07 12:16:24 +02:00
commit e5625c6930
8 changed files with 178 additions and 28 deletions

View file

@ -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
View file

@ -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"

View file

@ -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

View file

@ -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
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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