mirror of
https://github.com/c-cube/iter.git
synced 2025-12-05 19:00:31 -05:00
add ocamlformat; reformat; migrate off qtest
This commit is contained in:
parent
688689b18b
commit
fc254a5d89
27 changed files with 1498 additions and 1322 deletions
15
.ocamlformat
Normal file
15
.ocamlformat
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
version = 0.24.1
|
||||
profile=conventional
|
||||
margin=80
|
||||
if-then-else=k-r
|
||||
parens-ite=true
|
||||
parens-tuple=multi-line-only
|
||||
sequence-style=terminator
|
||||
type-decl=compact
|
||||
break-cases=toplevel
|
||||
cases-exp-indent=2
|
||||
field-space=tight-decl
|
||||
leading-nested-match-parens=true
|
||||
module-item-spacing=compact
|
||||
quiet=true
|
||||
ocaml-version=4.08.0
|
||||
15
Makefile
15
Makefile
|
|
@ -13,6 +13,10 @@ clean:
|
|||
doc:
|
||||
@dune build @doc
|
||||
|
||||
format:
|
||||
@dune build @fmt --auto-promote
|
||||
|
||||
DUNE_OPTS ?= --profile=release
|
||||
BENCH_TARGETS= benchs.exe bench_persistent_read.exe bench_persistent.exe
|
||||
|
||||
benchs:
|
||||
|
|
@ -21,10 +25,17 @@ benchs:
|
|||
dune exec "src/bench/$$i" ; done
|
||||
|
||||
build-benchs:
|
||||
@dune build $(addprefix src/bench/, $(BENCH_TARGETS))
|
||||
@dune build $(DUNE_OPTS) $(addprefix src/bench/, $(BENCH_TARGETS))
|
||||
|
||||
bench-persistent:
|
||||
@dune exec $(DUNE_OPTS) src/bench/bench_persistent.exe
|
||||
bench-persistent-read:
|
||||
@dune exec $(DUNE_OPTS) src/bench/bench_persistent_read.exe
|
||||
benchs:
|
||||
@dune exec $(DUNE_OPTS) src/bench/benchs.exe
|
||||
|
||||
examples:
|
||||
dune build examples/test_sexpr.exe
|
||||
dune exec examples/test_sexpr.exe
|
||||
|
||||
VERSION=$(shell awk '/^version:/ {print $$2}' iter.opam)
|
||||
|
||||
|
|
|
|||
12
dune
12
dune
|
|
@ -1,8 +1,8 @@
|
|||
|
||||
(alias
|
||||
(name runtest)
|
||||
(deps (:dep README.md))
|
||||
(action (progn
|
||||
(rule
|
||||
(alias runtest)
|
||||
(deps
|
||||
(:dep README.md))
|
||||
(action
|
||||
(progn
|
||||
(run ocaml-mdx test %{dep})
|
||||
(diff? %{dep} %{dep}.corrected))))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
(lang dune 1.0)
|
||||
(lang dune 2.0)
|
||||
(name iter)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
|
||||
(executable
|
||||
(name test_sexpr)
|
||||
(libraries iter)
|
||||
(flags :standard -w +a-4-42-44-48-50-58-32-60@8 -safe-string -color always)
|
||||
(ocamlopt_flags :standard -O3 -color always
|
||||
-unbox-closures -unbox-closures-factor 20)
|
||||
)
|
||||
(ocamlopt_flags :standard -O3 -color always -unbox-closures
|
||||
-unbox-closures-factor 20))
|
||||
|
|
|
|||
|
|
@ -24,18 +24,26 @@ type t =
|
|||
| Atom of string (** An atom *)
|
||||
| List of t list (** A list of S-expressions *)
|
||||
|
||||
type token = [ `Open | `Close | `Atom of string ]
|
||||
(** Token that compose a Sexpr once serialized *)
|
||||
type token = [`Open | `Close | `Atom of string]
|
||||
|
||||
(** {2 Traverse an iterator of tokens} *)
|
||||
|
||||
(** Iterate on the S-expression, calling the callback with tokens *)
|
||||
let rec iter f s = match s with
|
||||
let rec iter f s =
|
||||
match s with
|
||||
| Atom a -> f (`Atom a)
|
||||
| List l -> f `Open; iter_list f l; f `Close
|
||||
and iter_list f l = match l with
|
||||
| List l ->
|
||||
f `Open;
|
||||
iter_list f l;
|
||||
f `Close
|
||||
|
||||
and iter_list f l =
|
||||
match l with
|
||||
| [] -> ()
|
||||
| x::l' -> iter f x; iter_list f l'
|
||||
| x :: l' ->
|
||||
iter f x;
|
||||
iter_list f l'
|
||||
|
||||
(** Traverse. This yields an iterator of tokens *)
|
||||
let traverse s = Iter.from_iter (fun k -> iter k s)
|
||||
|
|
@ -47,11 +55,17 @@ let traverse s = Iter.from_iter (fun k -> iter k s)
|
|||
let validate seq =
|
||||
let depth = ref 0 in
|
||||
Iter.map
|
||||
(fun tok -> match tok with
|
||||
| `Open -> incr depth; tok
|
||||
| `Close -> if !depth = 0
|
||||
then raise (Invalid_argument "wrong parenthesing")
|
||||
else decr depth; tok
|
||||
(fun tok ->
|
||||
match tok with
|
||||
| `Open ->
|
||||
incr depth;
|
||||
tok
|
||||
| `Close ->
|
||||
if !depth = 0 then
|
||||
raise (Invalid_argument "wrong parenthesing")
|
||||
else
|
||||
decr depth;
|
||||
tok
|
||||
| _ -> tok)
|
||||
seq
|
||||
|
||||
|
|
@ -66,18 +80,22 @@ let lex input =
|
|||
let rec next c =
|
||||
match c with
|
||||
| '(' -> k `Open
|
||||
| ')' -> flush_word(); k `Close
|
||||
| ')' ->
|
||||
flush_word ();
|
||||
k `Close
|
||||
| ' ' | '\t' | '\n' -> flush_word ()
|
||||
| c -> in_word := true; Buffer.add_char buf c
|
||||
| c ->
|
||||
in_word := true;
|
||||
Buffer.add_char buf c
|
||||
(* finish the previous word token *)
|
||||
and flush_word () =
|
||||
if !in_word then begin
|
||||
if !in_word then (
|
||||
(* this whitespace follows a word *)
|
||||
let word = Buffer.contents buf in
|
||||
Buffer.clear buf;
|
||||
in_word := false;
|
||||
k (`Atom word)
|
||||
end
|
||||
)
|
||||
in
|
||||
Iter.iter next input
|
||||
in
|
||||
|
|
@ -86,28 +104,31 @@ let lex input =
|
|||
(** Build a Sexpr from an iterator of tokens *)
|
||||
let of_seq seq =
|
||||
(* called on every token *)
|
||||
let rec k stack token = match token with
|
||||
let rec k stack token =
|
||||
match token with
|
||||
| `Open -> `Open :: stack
|
||||
| `Close -> collapse [] stack
|
||||
| `Atom a -> (`Expr (Atom a)) :: stack
|
||||
| `Atom a -> `Expr (Atom a) :: stack
|
||||
(* collapse last list into an `Expr *)
|
||||
and collapse acc stack = match stack with
|
||||
| `Open::stack' -> `Expr (List acc) :: stack'
|
||||
| `Expr a::stack' -> collapse (a :: acc) stack'
|
||||
and collapse acc stack =
|
||||
match stack with
|
||||
| `Open :: stack' -> `Expr (List acc) :: stack'
|
||||
| `Expr a :: stack' -> collapse (a :: acc) stack'
|
||||
| _ -> assert false
|
||||
in
|
||||
(* iterate, given an empty initial stack *)
|
||||
let stack = Iter.fold k [] seq in
|
||||
(* stack should contain exactly one expression *)
|
||||
match stack with
|
||||
| [`Expr expr] -> expr
|
||||
| [ `Expr expr ] -> expr
|
||||
| [] -> failwith "no Sexpr could be parsed"
|
||||
| _ -> failwith "too many elements on the stack"
|
||||
|
||||
(** {2 Printing} *)
|
||||
|
||||
(** Print a token on the given formatter *)
|
||||
let pp_token formatter token = match token with
|
||||
let pp_token formatter token =
|
||||
match token with
|
||||
| `Open -> Format.fprintf formatter "@[("
|
||||
| `Close -> Format.fprintf formatter ")@]"
|
||||
| `Atom s -> Format.pp_print_string formatter s
|
||||
|
|
@ -119,19 +140,28 @@ let pp_tokens formatter tokens =
|
|||
Iter.iter
|
||||
(fun token ->
|
||||
(match token with
|
||||
| `Open -> (if not !first then Format.fprintf formatter " "); first := true
|
||||
| `Close -> first := false; last := true
|
||||
| _ -> if !first then first := false else Format.fprintf formatter " ");
|
||||
| `Open ->
|
||||
if not !first then Format.fprintf formatter " ";
|
||||
first := true
|
||||
| `Close ->
|
||||
first := false;
|
||||
last := true
|
||||
| _ ->
|
||||
if !first then
|
||||
first := false
|
||||
else
|
||||
Format.fprintf formatter " ");
|
||||
pp_token formatter token;
|
||||
if !last then last := false)
|
||||
tokens
|
||||
|
||||
(** Pretty-print the S-expr. If [indent] is true, the S-expression
|
||||
is printed with indentation. *)
|
||||
let pp_sexpr ?(indent=false) formatter s =
|
||||
if indent
|
||||
then Format.fprintf formatter "@[<hov 4>%a@]" pp_tokens (traverse s)
|
||||
else pp_tokens formatter (traverse s)
|
||||
let pp_sexpr ?(indent = false) formatter s =
|
||||
if indent then
|
||||
Format.fprintf formatter "@[<hov 4>%a@]" pp_tokens (traverse s)
|
||||
else
|
||||
pp_tokens formatter (traverse s)
|
||||
|
||||
(** {2 Serializing} *)
|
||||
|
||||
|
|
@ -166,63 +196,69 @@ type 'a parser =
|
|||
|
||||
exception ParseFailure of string
|
||||
|
||||
let (>>=) p f = Bind (p, f)
|
||||
|
||||
let (>>) p p' = p >>= fun _ -> p'
|
||||
|
||||
let ( >>= ) p f = Bind (p, f)
|
||||
let ( >> ) p p' = p >>= fun _ -> p'
|
||||
let return x = Return x
|
||||
|
||||
let fail reason = Fail reason
|
||||
|
||||
let one f = One f
|
||||
|
||||
let skip = One (fun _ -> ())
|
||||
|
||||
let lookahead f = Zero f
|
||||
|
||||
let left = One (function | `Open -> ()
|
||||
let left =
|
||||
One
|
||||
(function
|
||||
| `Open -> ()
|
||||
| _ -> raise (ParseFailure "expected '('"))
|
||||
|
||||
let right = One (function | `Close -> ()
|
||||
let right =
|
||||
One
|
||||
(function
|
||||
| `Close -> ()
|
||||
| _ -> raise (ParseFailure "expected ')'"))
|
||||
|
||||
let pair f g =
|
||||
f >>= fun x ->
|
||||
g >>= fun y ->
|
||||
return (x, y)
|
||||
g >>= fun y -> return (x, y)
|
||||
|
||||
let triple f g h =
|
||||
f >>= fun x ->
|
||||
g >>= fun y ->
|
||||
h >>= fun z ->
|
||||
return (x, y, z)
|
||||
h >>= fun z -> return (x, y, z)
|
||||
|
||||
(** [(name,p) ^|| p'] behaves as p if the next token is [`Atom name], and
|
||||
like [p'] otherwise *)
|
||||
let (^||) (name,p) p' =
|
||||
lookahead
|
||||
(fun token -> match token with
|
||||
let ( ^|| ) (name, p) p' =
|
||||
lookahead (fun token ->
|
||||
match token with
|
||||
| `Atom s when s = name -> skip >> p ()
|
||||
| _ -> p')
|
||||
|
||||
(** Maps the value returned by the parser *)
|
||||
let map p f = p >>= fun x -> return (f x)
|
||||
|
||||
let p_str = one
|
||||
(function | `Atom s -> s | _ -> raise (ParseFailure "expected string"))
|
||||
let p_str =
|
||||
one (function
|
||||
| `Atom s -> s
|
||||
| _ -> raise (ParseFailure "expected string"))
|
||||
|
||||
let p_int = one
|
||||
(function | `Atom s -> (try int_of_string s
|
||||
let p_int =
|
||||
one (function
|
||||
| `Atom s ->
|
||||
(try int_of_string s
|
||||
with Failure _ -> raise (ParseFailure "expected int"))
|
||||
| _ -> raise (ParseFailure "expected int"))
|
||||
|
||||
let p_bool = one
|
||||
(function | `Atom s -> (try bool_of_string s
|
||||
let p_bool =
|
||||
one (function
|
||||
| `Atom s ->
|
||||
(try bool_of_string s
|
||||
with Failure _ -> raise (ParseFailure "expected bool"))
|
||||
| _ -> raise (ParseFailure "expected bool"))
|
||||
|
||||
let p_float = one
|
||||
(function | `Atom s -> (try float_of_string s
|
||||
let p_float =
|
||||
one (function
|
||||
| `Atom s ->
|
||||
(try float_of_string s
|
||||
with Failure _ -> raise (ParseFailure "expected float"))
|
||||
| _ -> raise (ParseFailure "expected float"))
|
||||
|
||||
|
|
@ -232,15 +268,13 @@ let many p =
|
|||
| `Close -> return []
|
||||
| _ ->
|
||||
p >>= fun x ->
|
||||
lookahead elements >>= fun l ->
|
||||
return (x :: l)
|
||||
lookahead elements >>= fun l -> return (x :: l)
|
||||
in
|
||||
left >> lookahead elements >>= fun l -> right >> return l
|
||||
|
||||
let many1 p =
|
||||
p >>= fun x ->
|
||||
many p >>= fun l ->
|
||||
return (x::l)
|
||||
many p >>= fun l -> return (x :: l)
|
||||
|
||||
(** parsing state that returns a 'a *)
|
||||
type 'a state =
|
||||
|
|
@ -251,14 +285,21 @@ type 'a state =
|
|||
on every parsed value. The callback decides whether to push another
|
||||
state or whether to continue. *)
|
||||
let parse_k p tokens k =
|
||||
let rec state = Push(p, fun x -> match k x with `Stop -> Bottom | `Continue -> state) in
|
||||
let rec state =
|
||||
Push
|
||||
( p,
|
||||
fun x ->
|
||||
match k x with
|
||||
| `Stop -> Bottom
|
||||
| `Continue -> state )
|
||||
in
|
||||
(* Token handler. It also takes the current parser. *)
|
||||
let rec one_step state token =
|
||||
match reduce state with
|
||||
| Bottom -> (* should not happen, unless there are too many tokens *)
|
||||
| Bottom ->
|
||||
(* should not happen, unless there are too many tokens *)
|
||||
raise (ParseFailure "unexpected ')'")
|
||||
| Push (Return _, _cont) ->
|
||||
assert false (* should be reduced *)
|
||||
| Push (Return _, _cont) -> assert false (* should be reduced *)
|
||||
| Push (Zero f, cont) ->
|
||||
let p' = f token in
|
||||
let state' = Push (p', cont) in
|
||||
|
|
@ -277,7 +318,8 @@ let parse_k p tokens k =
|
|||
one_step state' token (* do not consume token *)
|
||||
| Push (Fail reason, _) -> raise (ParseFailure reason)
|
||||
(* Reduce parser state *)
|
||||
and reduce state = match state with
|
||||
and reduce state =
|
||||
match state with
|
||||
| Push (Return x, cont) ->
|
||||
let state' = cont x in
|
||||
reduce state'
|
||||
|
|
@ -289,7 +331,9 @@ let parse_k p tokens k =
|
|||
(** Parse one value *)
|
||||
let parse p tokens =
|
||||
let res = ref None in
|
||||
parse_k p tokens (fun x -> res := Some x; `Stop);
|
||||
parse_k p tokens (fun x ->
|
||||
res := Some x;
|
||||
`Stop);
|
||||
(* return result *)
|
||||
match !res with
|
||||
| None -> raise (ParseFailure "incomplete input")
|
||||
|
|
@ -298,7 +342,8 @@ let parse p tokens =
|
|||
(** Parse an iterator of values *)
|
||||
let parse_seq p tokens =
|
||||
let seq_fun k =
|
||||
parse_k p tokens (fun x -> k x; `Continue)
|
||||
parse_k p tokens (fun x ->
|
||||
k x;
|
||||
`Continue)
|
||||
in
|
||||
Iter.from_iter seq_fun
|
||||
|
||||
|
|
|
|||
|
|
@ -20,24 +20,24 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|||
|
||||
(* {1 Basic S-expressions, with printing and parsing} *)
|
||||
|
||||
(** S-expression *)
|
||||
type t =
|
||||
| Atom of string (** An atom *)
|
||||
| List of t list (** A list of S-expressions *)
|
||||
(** S-expression *)
|
||||
|
||||
type token = [`Open | `Close | `Atom of string]
|
||||
(** Token that compose a Sexpr once serialized *)
|
||||
type token = [ `Open | `Close | `Atom of string ]
|
||||
(** Token that compose a Sexpr once serialized *)
|
||||
|
||||
(** {2 Traverse an iterator of tokens} *)
|
||||
|
||||
val iter : (token -> unit) -> t -> unit
|
||||
(** Iterate on the S-expression, calling the callback with tokens *)
|
||||
(** Iterate on the S-expression, calling the callback with tokens *)
|
||||
|
||||
val traverse : t -> token Iter.t
|
||||
(** Traverse. This yields an iterator of tokens *)
|
||||
(** Traverse. This yields an iterator of tokens *)
|
||||
|
||||
val validate : token Iter.t -> token Iter.t
|
||||
(** Returns the same iterator of tokens, but during iteration, if
|
||||
(** Returns the same iterator of tokens, but during iteration, if
|
||||
the structure of the Sexpr corresponding to the iterator
|
||||
is wrong (bad parenthesing), Invalid_argument is raised
|
||||
and iteration is stoped *)
|
||||
|
|
@ -45,30 +45,30 @@ val validate : token Iter.t -> token Iter.t
|
|||
(** {2 Text <-> tokens} *)
|
||||
|
||||
val lex : char Iter.t -> token Iter.t
|
||||
(** Lex: create an iterator of tokens from the given iterator of chars. *)
|
||||
(** Lex: create an iterator of tokens from the given iterator of chars. *)
|
||||
|
||||
val of_seq : token Iter.t -> t
|
||||
(** Build a Sexpr from an iterator of tokens, or raise Failure *)
|
||||
(** Build a Sexpr from an iterator of tokens, or raise Failure *)
|
||||
|
||||
(** {2 Printing} *)
|
||||
|
||||
val pp_token : Format.formatter -> token -> unit
|
||||
(** Print a token on the given formatter *)
|
||||
(** Print a token on the given formatter *)
|
||||
|
||||
val pp_tokens : Format.formatter -> token Iter.t -> unit
|
||||
(** Print an iterator of Sexpr tokens on the given formatter *)
|
||||
(** Print an iterator of Sexpr tokens on the given formatter *)
|
||||
|
||||
val pp_sexpr : ?indent:bool -> Format.formatter -> t -> unit
|
||||
(** Pretty-print the S-expr. If [indent] is true, the S-expression
|
||||
(** Pretty-print the S-expr. If [indent] is true, the S-expression
|
||||
is printed with indentation. *)
|
||||
|
||||
(** {2 Serializing} *)
|
||||
|
||||
val output_seq : string -> token Iter.t -> (token -> unit) -> unit
|
||||
(** print a pair "(name @,iterator)" *)
|
||||
(** print a pair "(name @,iterator)" *)
|
||||
|
||||
val output_str : string -> string -> (token -> unit) -> unit
|
||||
(** print a pair "(name str)" *)
|
||||
(** print a pair "(name str)" *)
|
||||
|
||||
(** {2 Parsing} *)
|
||||
|
||||
|
|
@ -79,54 +79,53 @@ type 'a parser
|
|||
|
||||
exception ParseFailure of string
|
||||
|
||||
val (>>=) : 'a parser -> ('a -> 'b parser) -> 'b parser
|
||||
(** Monadic bind: computes a parser from the result of
|
||||
val ( >>= ) : 'a parser -> ('a -> 'b parser) -> 'b parser
|
||||
(** Monadic bind: computes a parser from the result of
|
||||
the first parser *)
|
||||
|
||||
val (>>) : 'a parser -> 'b parser -> 'b parser
|
||||
(** Like (>>=), but ignores the result of the first parser *)
|
||||
val ( >> ) : 'a parser -> 'b parser -> 'b parser
|
||||
(** Like (>>=), but ignores the result of the first parser *)
|
||||
|
||||
val return : 'a -> 'a parser
|
||||
(** Parser that consumes no input and return the given value *)
|
||||
(** Parser that consumes no input and return the given value *)
|
||||
|
||||
val fail : string -> 'a parser
|
||||
(** Fails parsing with the given message *)
|
||||
(** Fails parsing with the given message *)
|
||||
|
||||
val one : (token -> 'a) -> 'a parser
|
||||
(** consumes one token with the function *)
|
||||
(** consumes one token with the function *)
|
||||
|
||||
val skip : unit parser
|
||||
(** Skip the token *)
|
||||
(** Skip the token *)
|
||||
|
||||
val lookahead : (token -> 'a parser) -> 'a parser
|
||||
(** choose parser given current token *)
|
||||
(** choose parser given current token *)
|
||||
|
||||
val left : unit parser
|
||||
(** Parses a `Open *)
|
||||
(** Parses a `Open *)
|
||||
|
||||
val right : unit parser
|
||||
(** Parses a `Close *)
|
||||
(** Parses a `Close *)
|
||||
|
||||
val pair : 'a parser -> 'b parser -> ('a * 'b) parser
|
||||
val triple : 'a parser -> 'b parser -> 'c parser -> ('a * 'b * 'c) parser
|
||||
|
||||
val (^||) : (string * (unit -> 'a parser)) -> 'a parser -> 'a parser
|
||||
(** [(name,p) ^|| p'] behaves as [p ()] if the next token is [`Atom name], and
|
||||
val ( ^|| ) : string * (unit -> 'a parser) -> 'a parser -> 'a parser
|
||||
(** [(name,p) ^|| p'] behaves as [p ()] if the next token is [`Atom name], and
|
||||
like [p'] otherwise *)
|
||||
|
||||
val map : 'a parser -> ('a -> 'b) -> 'b parser
|
||||
(** Maps the value returned by the parser *)
|
||||
(** Maps the value returned by the parser *)
|
||||
|
||||
val p_str : string parser
|
||||
val p_int : int parser
|
||||
val p_bool : bool parser
|
||||
|
||||
val many : 'a parser -> 'a list parser
|
||||
val many1 : 'a parser -> 'a list parser
|
||||
|
||||
val parse : 'a parser -> token Iter.t -> 'a
|
||||
(** Parses exactly one value from the iterator of tokens. Raises
|
||||
(** Parses exactly one value from the iterator of tokens. Raises
|
||||
ParseFailure if anything goes wrong. *)
|
||||
|
||||
val parse_seq : 'a parser -> token Iter.t -> 'a Iter.t
|
||||
(** Parses an iterator of values *)
|
||||
(** Parses an iterator of values *)
|
||||
|
|
|
|||
|
|
@ -1,59 +1,85 @@
|
|||
|
||||
(** {2 Test iterators} *)
|
||||
|
||||
(** print a list of items using the printing function *)
|
||||
let pp_list ?(sep=", ") pp_item formatter l =
|
||||
let pp_list ?(sep = ", ") pp_item formatter l =
|
||||
Iter.pp_seq ~sep pp_item formatter (Iter.of_list l)
|
||||
|
||||
(** Set of integers *)
|
||||
module ISet = Set.Make(struct type t = int let compare = compare end)
|
||||
module ISet = Set.Make (struct
|
||||
type t = int
|
||||
|
||||
let compare = compare
|
||||
end)
|
||||
|
||||
let iset = (module ISet : Set.S with type elt = int and type t = ISet.t)
|
||||
|
||||
module OrderedString = struct type t = string let compare = compare end
|
||||
module SMap = Iter.Map.Make(OrderedString)
|
||||
module OrderedString = struct
|
||||
type t = string
|
||||
|
||||
let my_map = SMap.of_seq (Iter.of_list ["1", 1; "2", 2; "3", 3; "answer", 42])
|
||||
let compare = compare
|
||||
end
|
||||
|
||||
module SMap = Iter.Map.Make (OrderedString)
|
||||
|
||||
let my_map = SMap.of_seq (Iter.of_list [ "1", 1; "2", 2; "3", 3; "answer", 42 ])
|
||||
let sexpr = "(foo bar (bazz quux hello 42) world (zoo foo bar (1 2 (3 4))))"
|
||||
|
||||
type term = | Lambda of term | Const of string | Var of int | Apply of term * term
|
||||
type term =
|
||||
| Lambda of term
|
||||
| Const of string
|
||||
| Var of int
|
||||
| Apply of term * term
|
||||
|
||||
let random_term () =
|
||||
let max = 10
|
||||
and num = ref 0 in
|
||||
let max = 10 and num = ref 0 in
|
||||
let rec build depth =
|
||||
if depth > 4 || !num > max then Const (random_const ()) else
|
||||
if depth > 4 || !num > max then
|
||||
Const (random_const ())
|
||||
else (
|
||||
match Random.int 6 with
|
||||
| 0 -> if depth > 0 then Var (Random.int depth) else Const (random_const ())
|
||||
| 1 -> incr num; Lambda (build (depth+1))
|
||||
| 0 ->
|
||||
if depth > 0 then
|
||||
Var (Random.int depth)
|
||||
else
|
||||
Const (random_const ())
|
||||
| 1 ->
|
||||
incr num;
|
||||
Lambda (build (depth + 1))
|
||||
| 2 -> Const (random_const ())
|
||||
| _ -> incr num; Apply ((build depth), (build depth))
|
||||
and random_const () = [|"a"; "b"; "c"; "f"; "g"; "h"|].(Random.int 6)
|
||||
in build 0
|
||||
| _ ->
|
||||
incr num;
|
||||
Apply (build depth, build depth)
|
||||
)
|
||||
and random_const () = [| "a"; "b"; "c"; "f"; "g"; "h" |].(Random.int 6) in
|
||||
build 0
|
||||
|
||||
let rec sexpr_of_term t =
|
||||
let f t k = match t with
|
||||
let f t k =
|
||||
match t with
|
||||
| Var i -> Sexpr.output_str "var" (string_of_int i) k
|
||||
| Lambda t' -> Sexpr.output_seq "lambda" (sexpr_of_term t') k
|
||||
| Apply (t1, t2) -> Sexpr.output_seq "apply" (Iter.append (sexpr_of_term t1) (sexpr_of_term t2)) k
|
||||
| Apply (t1, t2) ->
|
||||
Sexpr.output_seq "apply"
|
||||
(Iter.append (sexpr_of_term t1) (sexpr_of_term t2))
|
||||
k
|
||||
| Const s -> Sexpr.output_str "const" s k
|
||||
in Iter.from_iter (f t)
|
||||
in
|
||||
Iter.from_iter (f t)
|
||||
|
||||
let term_parser =
|
||||
let open Sexpr in
|
||||
let rec p_term () =
|
||||
left >>
|
||||
(("lambda", p_lambda) ^|| ("var", p_var) ^|| ("const", p_const) ^||
|
||||
("apply", p_apply) ^|| fail "bad term") >>= fun x ->
|
||||
right >> return x
|
||||
left
|
||||
>> ("lambda", p_lambda) ^|| ("var", p_var) ^|| ("const", p_const)
|
||||
^|| ("apply", p_apply) ^|| fail "bad term"
|
||||
>>= fun x -> right >> return x
|
||||
and p_apply () =
|
||||
p_term () >>= fun x ->
|
||||
p_term () >>= fun y ->
|
||||
return (Apply (x,y))
|
||||
p_term () >>= fun y -> return (Apply (x, y))
|
||||
and p_var () = p_int >>= fun i -> return (Var i)
|
||||
and p_const () = p_str >>= fun s -> return (Const s)
|
||||
and p_lambda () = p_term () >>= fun t -> return (Lambda t)
|
||||
in p_term ()
|
||||
and p_lambda () = p_term () >>= fun t -> return (Lambda t) in
|
||||
p_term ()
|
||||
|
||||
let term_of_sexp seq = Sexpr.parse term_parser seq
|
||||
|
||||
|
|
@ -67,65 +93,80 @@ let test_term () =
|
|||
|
||||
let _ =
|
||||
(* lists *)
|
||||
let l = [0;1;2;3;4;5;6] in
|
||||
let l' = Iter.to_list
|
||||
(Iter.filter (fun x -> x mod 2 = 0) (Iter.of_list l)) in
|
||||
let l'' = Iter.to_list
|
||||
(Iter.take 3 (Iter.drop 1 (Iter.of_list l))) in
|
||||
let l = [ 0; 1; 2; 3; 4; 5; 6 ] in
|
||||
let l' = Iter.to_list (Iter.filter (fun x -> x mod 2 = 0) (Iter.of_list l)) in
|
||||
let l'' = Iter.to_list (Iter.take 3 (Iter.drop 1 (Iter.of_list l))) in
|
||||
let h = Hashtbl.create 3 in
|
||||
for i = 0 to 5 do
|
||||
Hashtbl.add h i (i*i);
|
||||
Hashtbl.add h i (i * i)
|
||||
done;
|
||||
let l2 = Iter.to_list
|
||||
(Iter.map (fun (x, y) -> (string_of_int x) ^ " -> " ^ (string_of_int y))
|
||||
let l2 =
|
||||
Iter.to_list
|
||||
(Iter.map
|
||||
(fun (x, y) -> string_of_int x ^ " -> " ^ string_of_int y)
|
||||
(Iter.of_hashtbl h))
|
||||
in
|
||||
let l3 = Iter.to_list (Iter.rev (Iter.int_range ~start:0 ~stop:42)) in
|
||||
let set = List.fold_left (fun set x -> ISet.add x set) ISet.empty [4;3;100;42] in
|
||||
let set =
|
||||
List.fold_left (fun set x -> ISet.add x set) ISet.empty [ 4; 3; 100; 42 ]
|
||||
in
|
||||
let l4 = Iter.to_list (Iter.of_set iset set) in
|
||||
Format.printf "l=@[<h>[%a]@]@." (pp_list Format.pp_print_int) l;
|
||||
Format.printf "l'=@[<h>[%a]@]@." (pp_list Format.pp_print_int) l';
|
||||
Format.printf "l''=@[<h>[%a]@]@." (pp_list Format.pp_print_int) l'';
|
||||
Format.printf "l2=@[<h>[%a]@]@." (pp_list Format.pp_print_string) l2;
|
||||
Format.printf "l3=@[<h>[%a]@]@." (pp_list Format.pp_print_int) l3;
|
||||
Format.printf "s={@[<h>%a@]}@." (Iter.pp_seq Format.pp_print_int) (Iter.of_set iset set);
|
||||
Format.printf "s={@[<h>%a@]}@."
|
||||
(Iter.pp_seq Format.pp_print_int)
|
||||
(Iter.of_set iset set);
|
||||
Format.printf "l4=@[<h>[%a]@]@." (pp_list Format.pp_print_int) l4;
|
||||
Format.printf "l3[:5]+l4=@[<h>[%a]@]@." (Iter.pp_seq Format.pp_print_int)
|
||||
Format.printf "l3[:5]+l4=@[<h>[%a]@]@."
|
||||
(Iter.pp_seq Format.pp_print_int)
|
||||
(Iter.of_array
|
||||
(Iter.to_array (Iter.append
|
||||
(Iter.take 5 (Iter.of_list l3)) (Iter.of_list l4))));
|
||||
(Iter.to_array
|
||||
(Iter.append (Iter.take 5 (Iter.of_list l3)) (Iter.of_list l4))));
|
||||
(* iterator, persistent, etc *)
|
||||
let seq = Iter.int_range ~start:0 ~stop:100000 in
|
||||
let seq' = Iter.persistent seq in
|
||||
let stream = Iter.to_stream seq' in
|
||||
Format.printf "test length [0..100000]: persistent1 %d, stream %d, persistent2 %d"
|
||||
(Iter.length seq') (Iter.length (Iter.of_stream stream)) (Iter.length seq');
|
||||
Format.printf
|
||||
"test length [0..100000]: persistent1 %d, stream %d, persistent2 %d"
|
||||
(Iter.length seq') (Iter.length seq') (Iter.length seq');
|
||||
(* maps *)
|
||||
Format.printf "@[<h>map: %a@]@."
|
||||
(Iter.pp_seq (fun formatter (k,v) -> Format.fprintf formatter "\"%s\" -> %d" k v))
|
||||
(Iter.pp_seq (fun formatter (k, v) ->
|
||||
Format.fprintf formatter "\"%s\" -> %d" k v))
|
||||
(SMap.to_seq my_map);
|
||||
let module MyMapSeq = Iter.Map.Adapt(Map.Make(OrderedString)) in
|
||||
let my_map' = MyMapSeq.of_seq (Iter.of_list ["1", 1; "2", 2; "3", 3; "answer", 42]) in
|
||||
let module MyMapSeq = Iter.Map.Adapt (Map.Make (OrderedString)) in
|
||||
let my_map' =
|
||||
MyMapSeq.of_seq (Iter.of_list [ "1", 1; "2", 2; "3", 3; "answer", 42 ])
|
||||
in
|
||||
Format.printf "@[<h>map: %a@]@."
|
||||
(Iter.pp_seq (fun formatter (k,v) -> Format.fprintf formatter "\"%s\" -> %d" k v))
|
||||
(Iter.pp_seq (fun formatter (k, v) ->
|
||||
Format.fprintf formatter "\"%s\" -> %d" k v))
|
||||
(MyMapSeq.to_seq my_map');
|
||||
(* sum *)
|
||||
let n = 1000000 in
|
||||
let sum = Iter.fold (+) 0 (Iter.take n (Iter.repeat 1)) in
|
||||
let sum = Iter.fold ( + ) 0 (Iter.take n (Iter.repeat 1)) in
|
||||
Format.printf "%dx1 = %d@." n sum;
|
||||
assert (n=sum);
|
||||
assert (n = sum);
|
||||
(* sexpr *)
|
||||
let s = Sexpr.of_seq (Sexpr.lex (Iter.of_str sexpr)) in
|
||||
let s = Sexpr.of_seq (Iter.map
|
||||
(function | `Atom s -> `Atom (String.capitalize_ascii s) | tok -> tok)
|
||||
let s =
|
||||
Sexpr.of_seq
|
||||
(Iter.map
|
||||
(function
|
||||
| `Atom s -> `Atom (String.capitalize_ascii s)
|
||||
| tok -> tok)
|
||||
(Sexpr.traverse s))
|
||||
in
|
||||
Format.printf "@[<hov2>transform @[<h>%s@] into @[<h>%a@]@]@." sexpr (Sexpr.pp_sexpr ~indent:false) s;
|
||||
Format.printf "@[<hov2>transform @[<h>%s@] into @[<h>%a@]@]@." sexpr
|
||||
(Sexpr.pp_sexpr ~indent:false)
|
||||
s;
|
||||
Format.printf "@[<hv2> cycle:%a@]@." Sexpr.pp_tokens
|
||||
(Iter.concat (Iter.take 10 (Iter.repeat (Sexpr.traverse s))));
|
||||
(* sexpr parsing/printing *)
|
||||
for i = 0 to 20 do
|
||||
Format.printf "%d-th term test@." i;
|
||||
test_term ();
|
||||
test_term ()
|
||||
done;
|
||||
()
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ depends: [
|
|||
"result"
|
||||
"seq"
|
||||
"ocaml" { >= "4.03.0" }
|
||||
"dune" { >= "1.1" }
|
||||
"dune" { >= "2.0" }
|
||||
"dune-configurator"
|
||||
"qcheck" {with-test}
|
||||
"qtest" {with-test}
|
||||
"qcheck-core" {with-test}
|
||||
"ounit2" {with-test}
|
||||
"mdx" {with-test & >= "1.3" }
|
||||
"odoc" {with-doc}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
|
||||
QTEST_PREAMBLE='open Iter_shims_;; '
|
||||
DONTTEST=../src/iterLabels.ml ../src/mkshims.ml ../src/bigarray/mkshims.ml
|
||||
QTESTABLE=$(filter-out $(DONTTEST), \
|
||||
$(wildcard ../src/*.ml) \
|
||||
$(wildcard ../src/*.mli) \
|
||||
)
|
||||
|
||||
qtest-gen:
|
||||
@rm run_qtest.ml 2>/dev/null || true
|
||||
@if which qtest > /dev/null ; then \
|
||||
qtest extract --preamble $(QTEST_PREAMBLE) \
|
||||
-o run_qtest.ml \
|
||||
$(QTESTABLE) 2> /dev/null ; \
|
||||
else touch run_qtest.ml ; \
|
||||
fi
|
||||
|
||||
.PHONY: qtest-gen
|
||||
22
qtest/dune
22
qtest/dune
|
|
@ -1,22 +0,0 @@
|
|||
|
||||
(rule
|
||||
(targets run_qtest.ml)
|
||||
(deps Makefile (source_tree ../src)) ; (glob_files ../src/**/*.ml{,i})))
|
||||
(mode fallback)
|
||||
;(libraries (qtest qcheck))
|
||||
(action
|
||||
(run make qtest-gen))
|
||||
)
|
||||
|
||||
(executable
|
||||
(name run_qtest)
|
||||
(flags :standard -warn-error -a+8 -safe-string -w -33)
|
||||
(libraries iter qcheck)
|
||||
)
|
||||
|
||||
(alias
|
||||
(name runtest)
|
||||
(deps run_qtest.exe)
|
||||
(action (run %{deps}))
|
||||
)
|
||||
|
||||
1065
src/Iter.ml
1065
src/Iter.ml
File diff suppressed because it is too large
Load diff
121
src/Iter.mli
121
src/Iter.mli
|
|
@ -1,9 +1,6 @@
|
|||
(** Simple and Efficient Iterators
|
||||
|
||||
(* This file is free software, part of iter. See file "license" for more details. *)
|
||||
|
||||
(** {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
|
||||
implementation relies on the assumption that an iterator can be iterated
|
||||
on as many times as needed; this choice allows for high performance
|
||||
|
|
@ -37,12 +34,6 @@ type +'a t = ('a -> unit) -> unit
|
|||
it will be applied to every element of the iterator successively. *)
|
||||
|
||||
type +'a iter = 'a t
|
||||
|
||||
(** {b NOTE} Type [('a, 'b) t2 = ('a -> 'b -> unit) -> unit]
|
||||
has been removed and subsumed by [('a * 'b) t]
|
||||
@since 1.0
|
||||
*)
|
||||
|
||||
type 'a equal = 'a -> 'a -> bool
|
||||
type 'a hash = 'a -> int
|
||||
|
||||
|
|
@ -118,7 +109,7 @@ val iter : ('a -> unit) -> 'a t -> unit
|
|||
Basically [iter f seq] is just [seq f]. *)
|
||||
|
||||
val iteri : (int -> 'a -> unit) -> 'a t -> unit
|
||||
(** Iterate on elements and their index in the iterator *)
|
||||
(** Iterate on elements and their index in the iterator *)
|
||||
|
||||
val for_each : 'a t -> ('a -> unit) -> unit
|
||||
(** Consume the iterator, passing all its arguments to the function.
|
||||
|
|
@ -311,15 +302,13 @@ val group_succ_by : ?eq:('a -> 'a -> bool) -> 'a t -> 'a list t
|
|||
{b note}: Order of items in each list is unspecified.
|
||||
@since 0.6 *)
|
||||
|
||||
val group_by : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) ->
|
||||
'a t -> 'a list t
|
||||
val group_by : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) -> 'a t -> 'a list t
|
||||
(** Group equal elements, disregarding their order of appearance.
|
||||
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
||||
{b note}: Order of items in each list is unspecified.
|
||||
@since 0.6 *)
|
||||
|
||||
val count : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) ->
|
||||
'a t -> ('a * int) t
|
||||
val count : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) -> 'a t -> ('a * int) t
|
||||
(** Map each distinct element to its number of occurrences in the whole seq.
|
||||
Similar to [group_by seq |> map (fun l->List.hd l, List.length l)]
|
||||
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
||||
|
|
@ -351,8 +340,11 @@ val join : join_row:('a -> 'b -> 'c option) -> 'a t -> 'b t -> 'c t
|
|||
the two elements do not combine. Assume that [b] allows for multiple
|
||||
iterations. *)
|
||||
|
||||
val join_by : ?eq:'key equal -> ?hash:'key hash ->
|
||||
('a -> 'key) -> ('b -> 'key) ->
|
||||
val join_by :
|
||||
?eq:'key equal ->
|
||||
?hash:'key hash ->
|
||||
('a -> 'key) ->
|
||||
('b -> 'key) ->
|
||||
merge:('key -> 'a -> 'b -> 'c option) ->
|
||||
'a t ->
|
||||
'b t ->
|
||||
|
|
@ -366,8 +358,11 @@ val join_by : ?eq:'key equal -> ?hash:'key hash ->
|
|||
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
||||
@since 0.10 *)
|
||||
|
||||
val join_all_by : ?eq:'key equal -> ?hash:'key hash ->
|
||||
('a -> 'key) -> ('b -> 'key) ->
|
||||
val join_all_by :
|
||||
?eq:'key equal ->
|
||||
?hash:'key hash ->
|
||||
('a -> 'key) ->
|
||||
('b -> 'key) ->
|
||||
merge:('key -> 'a list -> 'b list -> 'c option) ->
|
||||
'a t ->
|
||||
'b t ->
|
||||
|
|
@ -383,7 +378,9 @@ val join_all_by : ?eq:'key equal -> ?hash:'key hash ->
|
|||
and [c] is inserted in the result.
|
||||
@since 0.10 *)
|
||||
|
||||
val group_join_by : ?eq:'a equal -> ?hash:'a hash ->
|
||||
val group_join_by :
|
||||
?eq:'a equal ->
|
||||
?hash:'a hash ->
|
||||
('b -> 'a) ->
|
||||
'a t ->
|
||||
'b t ->
|
||||
|
|
@ -398,9 +395,7 @@ val group_join_by : ?eq:'a equal -> ?hash:'a hash ->
|
|||
|
||||
(** {2 Set-like} *)
|
||||
|
||||
val inter :
|
||||
?eq:'a equal -> ?hash:'a hash ->
|
||||
'a t -> 'a t -> 'a t
|
||||
val inter : ?eq:'a equal -> ?hash:'a hash -> 'a t -> 'a t -> 'a t
|
||||
(** Intersection of two collections. Each element will occur at most once
|
||||
in the result. Eager.
|
||||
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
||||
|
|
@ -411,9 +406,7 @@ val inter :
|
|||
[] (inter (0--5) (6--10) |> to_list)
|
||||
*)
|
||||
|
||||
val union :
|
||||
?eq:'a equal -> ?hash:'a hash ->
|
||||
'a t -> 'a t -> 'a t
|
||||
val union : ?eq:'a equal -> ?hash:'a hash -> 'a t -> 'a t -> 'a t
|
||||
(** Union of two collections. Each element will occur at most once
|
||||
in the result. Eager.
|
||||
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
||||
|
|
@ -423,9 +416,7 @@ val union :
|
|||
[2;4;5;6] (union (4--6) (cons 2 (4--5)) |> sort |> to_list)
|
||||
*)
|
||||
|
||||
val diff :
|
||||
?eq:'a equal -> ?hash:'a hash ->
|
||||
'a t -> 'a t -> 'a t
|
||||
val diff : ?eq:'a equal -> ?hash:'a hash -> 'a t -> 'a t -> 'a t
|
||||
(** Set difference. Eager.
|
||||
@since 0.10 *)
|
||||
|
||||
|
|
@ -433,9 +424,7 @@ val diff :
|
|||
[1;2;8;9;10] (diff (1--10) (3--7) |> to_list)
|
||||
*)
|
||||
|
||||
val subset :
|
||||
?eq:'a equal -> ?hash:'a hash ->
|
||||
'a t -> 'a t -> bool
|
||||
val subset : ?eq:'a equal -> ?hash:'a hash -> 'a t -> 'a t -> bool
|
||||
(** [subset a b] returns [true] if all elements of [a] belong to [b]. Eager.
|
||||
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
||||
@since 0.10 *)
|
||||
|
|
@ -494,7 +483,7 @@ val take_while : ('a -> bool) -> 'a t -> 'a t
|
|||
Will work on an infinite iterator [s] if the predicate is false for at
|
||||
least one element of [s]. *)
|
||||
|
||||
val fold_while : ('a -> 'b -> 'a * [`Stop | `Continue]) -> 'a -> 'b t -> 'a
|
||||
val fold_while : ('a -> 'b -> 'a * [ `Stop | `Continue ]) -> 'a -> 'b t -> 'a
|
||||
(** Folds over elements of the iterator, stopping early if the accumulator
|
||||
returns [('a, `Stop)]
|
||||
@since 0.5.5 *)
|
||||
|
|
@ -517,9 +506,7 @@ val zip_i : 'a t -> (int * 'a) t
|
|||
(** {2 Pair iterators} *)
|
||||
|
||||
val fold2 : ('c -> 'a -> 'b -> 'c) -> 'c -> ('a * 'b) t -> 'c
|
||||
|
||||
val iter2 : ('a -> 'b -> unit) -> ('a * 'b) t -> unit
|
||||
|
||||
val map2 : ('a -> 'b -> 'c) -> ('a * 'b) t -> 'c t
|
||||
|
||||
val map2_2 : ('a -> 'b -> 'c) -> ('a -> 'b -> 'd) -> ('a * 'b) t -> ('c * 'd) t
|
||||
|
|
@ -604,7 +591,6 @@ val of_hashtbl : ('a, 'b) Hashtbl.t -> ('a * 'b) t
|
|||
|
||||
val hashtbl_keys : ('a, 'b) Hashtbl.t -> 'a t
|
||||
val hashtbl_values : ('a, 'b) Hashtbl.t -> 'b t
|
||||
|
||||
val of_str : string -> char t
|
||||
val to_str : char t -> string
|
||||
|
||||
|
|
@ -668,6 +654,7 @@ val to_gen : 'a t -> 'a gen
|
|||
module Set : sig
|
||||
module type S = sig
|
||||
include Set.S
|
||||
|
||||
val of_iter : elt iter -> t
|
||||
val to_iter : t -> elt iter
|
||||
val to_list : t -> elt list
|
||||
|
|
@ -681,10 +668,10 @@ module Set : sig
|
|||
end
|
||||
|
||||
(** Create an enriched Set module from the given one *)
|
||||
module Adapt(X : Set.S) : S with type elt = X.elt and type t = X.t
|
||||
module Adapt (X : Set.S) : S with type elt = X.elt and type t = X.t
|
||||
|
||||
(** Functor to build an extended Set module from an ordered type *)
|
||||
module Make(X : Set.OrderedType) : S with type elt = X.t
|
||||
module Make (X : Set.OrderedType) : S with type elt = X.t
|
||||
end
|
||||
|
||||
(** {2 Maps} *)
|
||||
|
|
@ -692,6 +679,7 @@ end
|
|||
module Map : sig
|
||||
module type S = sig
|
||||
include Map.S
|
||||
|
||||
val to_iter : 'a t -> (key * 'a) iter
|
||||
val of_iter : (key * 'a) iter -> 'a t
|
||||
val keys : 'a t -> key iter
|
||||
|
|
@ -707,10 +695,10 @@ module Map : sig
|
|||
end
|
||||
|
||||
(** Adapt a pre-existing Map module to make it iterator-aware *)
|
||||
module Adapt(M : Map.S) : S with type key = M.key and type 'a t = 'a M.t
|
||||
module Adapt (M : Map.S) : S with type key = M.key and type 'a t = 'a M.t
|
||||
|
||||
(** Create an enriched Map module, with iterator-aware functions *)
|
||||
module Make(V : Map.OrderedType) : S with type key = V.t
|
||||
module Make (V : Map.OrderedType) : S with type key = V.t
|
||||
end
|
||||
|
||||
(** {1 Random iterators} *)
|
||||
|
|
@ -747,7 +735,7 @@ val shuffle_buffer : int -> 'a t -> 'a t
|
|||
(** {2 Sampling} *)
|
||||
|
||||
val sample : int -> 'a t -> 'a array
|
||||
(** [sample n seq] returns k samples of [seq], with uniform probability.
|
||||
(** [sample n seq] returns k samples of [seq], with uniform probability.
|
||||
It will consume the iterator and use O(n) memory.
|
||||
|
||||
It returns an array of size [min (length seq) n].
|
||||
|
|
@ -756,28 +744,28 @@ val sample : int -> 'a t -> 'a array
|
|||
(** {1 Infix functions} *)
|
||||
|
||||
module Infix : sig
|
||||
val (--) : int -> int -> int t
|
||||
val ( -- ) : int -> int -> int t
|
||||
(** [a -- b] is the range of integers from [a] to [b], both included,
|
||||
in increasing order. It will therefore be empty if [a > b]. *)
|
||||
|
||||
val (--^) : int -> int -> int t
|
||||
val ( --^ ) : int -> int -> int t
|
||||
(** [a --^ b] is the range of integers from [b] to [a], both included,
|
||||
in decreasing order (starts from [a]).
|
||||
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}
|
||||
@since 0.5 *)
|
||||
|
||||
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
|
||||
val ( >|= ) : 'a t -> ('a -> 'b) -> 'b t
|
||||
(** 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)
|
||||
@since 0.5 *)
|
||||
|
||||
val (<+>) : 'a t -> 'a t -> 'a t
|
||||
val ( <+> ) : 'a t -> 'a t -> 'a t
|
||||
(** Concatenation of iterators
|
||||
@since 0.5 *)
|
||||
end
|
||||
|
|
@ -786,19 +774,22 @@ include module type of Infix
|
|||
|
||||
(** {1 Pretty printing} *)
|
||||
|
||||
val pp_seq : ?sep:string -> (Format.formatter -> 'a -> unit) ->
|
||||
Format.formatter -> 'a t -> unit
|
||||
val pp_seq :
|
||||
?sep:string ->
|
||||
(Format.formatter -> 'a -> unit) ->
|
||||
Format.formatter ->
|
||||
'a t ->
|
||||
unit
|
||||
(** Pretty print an iterator of ['a], using the given pretty printer
|
||||
to print each elements. An optional separator string can be provided. *)
|
||||
|
||||
val pp_buf : ?sep:string -> (Buffer.t -> 'a -> unit) ->
|
||||
Buffer.t -> 'a t -> unit
|
||||
val pp_buf : ?sep:string -> (Buffer.t -> 'a -> unit) -> Buffer.t -> 'a t -> unit
|
||||
(** Print into a buffer *)
|
||||
|
||||
val to_string : ?sep:string -> ('a -> string) -> 'a t -> string
|
||||
(** Print into a string *)
|
||||
|
||||
(** {1 Basic IO}
|
||||
(** Basic IO
|
||||
|
||||
Very basic interface to manipulate files as iterator of chunks/lines. The
|
||||
iterators take care of opening and closing files properly; every time
|
||||
|
|
@ -823,10 +814,8 @@ val to_string : ?sep:string -> ('a -> string) -> 'a t -> string
|
|||
]}
|
||||
|
||||
@since 0.5.1 *)
|
||||
|
||||
module IO : sig
|
||||
val lines_of : ?mode:int -> ?flags:open_flag list ->
|
||||
string -> string t
|
||||
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
|
||||
|
|
@ -836,29 +825,29 @@ module IO : sig
|
|||
@param mode default [0o644]
|
||||
@param flags default: [[Open_rdonly]] *)
|
||||
|
||||
val chunks_of : ?mode:int -> ?flags:open_flag list -> ?size:int ->
|
||||
string -> string t
|
||||
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 iterator 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
|
||||
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_bytes_to : ?mode:int -> ?flags:open_flag list ->
|
||||
string -> Bytes.t t -> unit
|
||||
val write_bytes_to :
|
||||
?mode:int -> ?flags:open_flag list -> string -> Bytes.t t -> unit
|
||||
(** @since 0.5.4 *)
|
||||
|
||||
val write_lines : ?mode:int -> ?flags:open_flag list ->
|
||||
string -> string t -> unit
|
||||
val write_lines :
|
||||
?mode:int -> ?flags:open_flag list -> string -> string t -> unit
|
||||
(** Same as {!write_to}, but intercales ['\n'] between each string *)
|
||||
|
||||
val write_bytes_lines : ?mode:int -> ?flags:open_flag list ->
|
||||
string -> Bytes.t t -> unit
|
||||
val write_bytes_lines :
|
||||
?mode:int -> ?flags:open_flag list -> string -> Bytes.t t -> unit
|
||||
(** @since 0.5.4 *)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
(* This file is free software, part of iterator. See file "license" for more details. *)
|
||||
|
||||
|
||||
(** {1 Simple and Efficient Iterators}
|
||||
|
||||
Version of {!Iterator} with labels
|
||||
|
|
@ -112,7 +110,8 @@ val fold_map : f:('acc -> 'a -> 'acc * 'b) -> init:'acc -> 'a t -> 'b t
|
|||
information to the map function.
|
||||
@since 0.9 *)
|
||||
|
||||
val fold_filter_map : f:('acc -> 'a -> 'acc * 'b option) -> init:'acc -> 'a t -> 'b t
|
||||
val fold_filter_map :
|
||||
f:('acc -> 'a -> 'acc * 'b option) -> init:'acc -> 'a t -> 'b t
|
||||
(** [fold_filter_map f acc l] is a {!fold_map}-like function, but the
|
||||
function can choose to skip an element by retuning [None].
|
||||
@since 0.9 *)
|
||||
|
|
@ -124,7 +123,7 @@ val mapi : f:(int -> 'a -> 'b) -> 'a t -> 'b t
|
|||
(** Map objects, along with their index in the iterator *)
|
||||
|
||||
val map_by_2 : f:('a -> 'a -> 'a) -> 'a t -> 'a t
|
||||
(** Map objects two by two. lazily.
|
||||
(** Map objects two by two. lazily.
|
||||
The last element is kept in the iterator if the count is odd.
|
||||
@since 0.7 *)
|
||||
|
||||
|
|
@ -171,7 +170,6 @@ val length : 'a t -> int
|
|||
val is_empty : 'a t -> bool
|
||||
(** Is the iterator empty? Forces the iterator. *)
|
||||
|
||||
|
||||
(** {2 Transformation} *)
|
||||
|
||||
val filter : f:('a -> bool) -> 'a t -> 'a t
|
||||
|
|
@ -275,15 +273,13 @@ val group_succ_by : ?eq:('a -> 'a -> bool) -> 'a t -> 'a list t
|
|||
Formerly synonym to [group].
|
||||
@since 0.6 *)
|
||||
|
||||
val group_by : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) ->
|
||||
'a t -> 'a list t
|
||||
val group_by : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) -> 'a t -> 'a list t
|
||||
(** Group equal elements, disregarding their order of appearance.
|
||||
The result iterator is traversable as many times as required.
|
||||
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
||||
@since 0.6 *)
|
||||
|
||||
val count : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) ->
|
||||
'a t -> ('a * int) t
|
||||
val count : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) -> 'a t -> ('a * int) t
|
||||
(** Map each distinct element to its number of occurrences in the whole seq.
|
||||
Similar to [group_by seq |> map (fun l->List.hd l, List.length l)]
|
||||
@since 0.10 *)
|
||||
|
|
@ -314,8 +310,11 @@ val join : join_row:('a -> 'b -> 'c option) -> 'a t -> 'b t -> 'c t
|
|||
the two elements do not combine. Assume that [b] allows for multiple
|
||||
iterations. *)
|
||||
|
||||
val join_by : ?eq:'key equal -> ?hash:'key hash ->
|
||||
('a -> 'key) -> ('b -> 'key) ->
|
||||
val join_by :
|
||||
?eq:'key equal ->
|
||||
?hash:'key hash ->
|
||||
('a -> 'key) ->
|
||||
('b -> 'key) ->
|
||||
merge:('key -> 'a -> 'b -> 'c option) ->
|
||||
'a t ->
|
||||
'b t ->
|
||||
|
|
@ -329,8 +328,11 @@ val join_by : ?eq:'key equal -> ?hash:'key hash ->
|
|||
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
||||
@since 0.10 *)
|
||||
|
||||
val join_all_by : ?eq:'key equal -> ?hash:'key hash ->
|
||||
('a -> 'key) -> ('b -> 'key) ->
|
||||
val join_all_by :
|
||||
?eq:'key equal ->
|
||||
?hash:'key hash ->
|
||||
('a -> 'key) ->
|
||||
('b -> 'key) ->
|
||||
merge:('key -> 'a list -> 'b list -> 'c option) ->
|
||||
'a t ->
|
||||
'b t ->
|
||||
|
|
@ -346,7 +348,9 @@ val join_all_by : ?eq:'key equal -> ?hash:'key hash ->
|
|||
and [c] is inserted in the result.
|
||||
@since 0.10 *)
|
||||
|
||||
val group_join_by : ?eq:'a equal -> ?hash:'a hash ->
|
||||
val group_join_by :
|
||||
?eq:'a equal ->
|
||||
?hash:'a hash ->
|
||||
('b -> 'a) ->
|
||||
'a t ->
|
||||
'b t ->
|
||||
|
|
@ -359,9 +363,7 @@ val group_join_by : ?eq:'a equal -> ?hash:'a hash ->
|
|||
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
||||
@since 0.10 *)
|
||||
|
||||
val inter :
|
||||
?eq:'a equal -> ?hash:'a hash ->
|
||||
'a t -> 'a t -> 'a t
|
||||
val inter : ?eq:'a equal -> ?hash:'a hash -> 'a t -> 'a t -> 'a t
|
||||
(** Intersection of two collections. Each element will occur at most once
|
||||
in the result. Eager.
|
||||
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
||||
|
|
@ -372,9 +374,7 @@ val inter :
|
|||
[] (inter (0--5) (6--10) |> to_list)
|
||||
*)
|
||||
|
||||
val union :
|
||||
?eq:'a equal -> ?hash:'a hash ->
|
||||
'a t -> 'a t -> 'a t
|
||||
val union : ?eq:'a equal -> ?hash:'a hash -> 'a t -> 'a t -> 'a t
|
||||
(** Union of two collections. Each element will occur at most once
|
||||
in the result. Eager.
|
||||
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
||||
|
|
@ -384,9 +384,7 @@ val union :
|
|||
[2;4;5;6] (union (4--6) (cons 2 (4--5)) |> sort |> to_list)
|
||||
*)
|
||||
|
||||
val diff :
|
||||
?eq:'a equal -> ?hash:'a hash ->
|
||||
'a t -> 'a t -> 'a t
|
||||
val diff : ?eq:'a equal -> ?hash:'a hash -> 'a t -> 'a t -> 'a t
|
||||
(** Set difference. Eager.
|
||||
@since 0.10 *)
|
||||
|
||||
|
|
@ -394,9 +392,7 @@ val diff :
|
|||
[1;2;8;9;10] (diff (1--10) (3--7) |> to_list)
|
||||
*)
|
||||
|
||||
val subset :
|
||||
?eq:'a equal -> ?hash:'a hash ->
|
||||
'a t -> 'a t -> bool
|
||||
val subset : ?eq:'a equal -> ?hash:'a hash -> 'a t -> 'a t -> bool
|
||||
(** [subset a b] returns [true] if all elements of [a] belong to [b]. Eager.
|
||||
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
||||
@since 0.10 *)
|
||||
|
|
@ -459,7 +455,8 @@ val take_while : f:('a -> bool) -> 'a t -> 'a t
|
|||
Will work on an infinite iterator [s] if the predicate is false for at
|
||||
least one element of [s]. *)
|
||||
|
||||
val fold_while : f:('a -> 'b -> 'a * [`Stop | `Continue]) -> init:'a -> 'b t -> 'a
|
||||
val fold_while :
|
||||
f:('a -> 'b -> 'a * [ `Stop | `Continue ]) -> init:'a -> 'b t -> 'a
|
||||
(** Folds over elements of the iterator, stopping early if the accumulator
|
||||
returns [('a, `Stop)]
|
||||
@since 0.5.5 *)
|
||||
|
|
@ -480,15 +477,13 @@ val zip_i : 'a t -> (int * 'a) t
|
|||
@since 1.0 Changed type to just give an iterator of pairs *)
|
||||
|
||||
val fold2 : f:('c -> 'a -> 'b -> 'c) -> init:'c -> ('a * 'b) t -> 'c
|
||||
|
||||
val iter2 : f:('a -> 'b -> unit) -> ('a * 'b) t -> unit
|
||||
|
||||
val map2 : f:('a -> 'b -> 'c) -> ('a * 'b) t -> 'c t
|
||||
|
||||
val map2_2 : f:('a -> 'b -> 'c) -> ('a -> 'b -> 'd) -> ('a * 'b) t -> ('c * 'd) t
|
||||
val map2_2 :
|
||||
f:('a -> 'b -> 'c) -> ('a -> 'b -> 'd) -> ('a * 'b) t -> ('c * 'd) t
|
||||
(** [map2_2 f g seq2] maps each [x, y] of seq2 into [f x y, g x y] *)
|
||||
|
||||
|
||||
(** {2 Data structures converters} *)
|
||||
|
||||
val to_list : 'a t -> 'a list
|
||||
|
|
@ -568,7 +563,6 @@ val of_hashtbl : ('a, 'b) Hashtbl.t -> ('a * 'b) t
|
|||
|
||||
val hashtbl_keys : ('a, 'b) Hashtbl.t -> 'a t
|
||||
val hashtbl_values : ('a, 'b) Hashtbl.t -> 'b t
|
||||
|
||||
val of_str : string -> char t
|
||||
val to_str : char t -> string
|
||||
|
||||
|
|
@ -633,6 +627,7 @@ val to_gen : 'a t -> 'a gen
|
|||
module Set : sig
|
||||
module type S = sig
|
||||
include Set.S
|
||||
|
||||
val of_iter : elt iter -> t
|
||||
val to_iter : t -> elt iter
|
||||
val to_list : t -> elt list
|
||||
|
|
@ -646,10 +641,10 @@ module Set : sig
|
|||
end
|
||||
|
||||
(** Create an enriched Set module from the given one *)
|
||||
module Adapt(X : Set.S) : S with type elt = X.elt and type t = X.t
|
||||
module Adapt (X : Set.S) : S with type elt = X.elt and type t = X.t
|
||||
|
||||
(** Functor to build an extended Set module from an ordered type *)
|
||||
module Make(X : Set.OrderedType) : S with type elt = X.t
|
||||
module Make (X : Set.OrderedType) : S with type elt = X.t
|
||||
end
|
||||
|
||||
(** {3 Maps} *)
|
||||
|
|
@ -657,6 +652,7 @@ end
|
|||
module Map : sig
|
||||
module type S = sig
|
||||
include Map.S
|
||||
|
||||
val to_iter : 'a t -> (key * 'a) iter
|
||||
val of_iter : (key * 'a) iter -> 'a t
|
||||
val keys : 'a t -> key iter
|
||||
|
|
@ -672,10 +668,10 @@ module Map : sig
|
|||
end
|
||||
|
||||
(** Adapt a pre-existing Map module to make it iterator-aware *)
|
||||
module Adapt(M : Map.S) : S with type key = M.key and type 'a t = 'a M.t
|
||||
module Adapt (M : Map.S) : S with type key = M.key and type 'a t = 'a M.t
|
||||
|
||||
(** Create an enriched Map module, with iterator-aware functions *)
|
||||
module Make(V : Map.OrderedType) : S with type key = V.t
|
||||
module Make (V : Map.OrderedType) : S with type key = V.t
|
||||
end
|
||||
|
||||
(** {2 Random iterators} *)
|
||||
|
|
@ -712,7 +708,7 @@ val shuffle_buffer : n:int -> 'a t -> 'a t
|
|||
(** {3 Sampling} *)
|
||||
|
||||
val sample : n:int -> 'a t -> 'a array
|
||||
(** [sample n seq] returns k samples of [seq], with uniform probability.
|
||||
(** [sample n seq] returns k samples of [seq], with uniform probability.
|
||||
It will consume the iterator and use O(n) memory.
|
||||
|
||||
It returns an array of size [min (length seq) n].
|
||||
|
|
@ -721,28 +717,28 @@ val sample : n:int -> 'a t -> 'a array
|
|||
(** {2 Infix functions} *)
|
||||
|
||||
module Infix : sig
|
||||
val (--) : int -> int -> int t
|
||||
val ( -- ) : int -> int -> int t
|
||||
(** [a -- b] is the range of integers from [a] to [b], both included,
|
||||
in increasing order. It will therefore be empty if [a > b]. *)
|
||||
|
||||
val (--^) : int -> int -> int t
|
||||
val ( --^ ) : int -> int -> int t
|
||||
(** [a --^ b] is the range of integers from [b] to [a], both included,
|
||||
in decreasing order (starts from [a]).
|
||||
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}
|
||||
@since 0.5 *)
|
||||
|
||||
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
|
||||
val ( >|= ) : 'a t -> ('a -> 'b) -> 'b t
|
||||
(** 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)
|
||||
@since 0.5 *)
|
||||
|
||||
val (<+>) : 'a t -> 'a t -> 'a t
|
||||
val ( <+> ) : 'a t -> 'a t -> 'a t
|
||||
(** Concatenation of iterators
|
||||
@since 0.5 *)
|
||||
end
|
||||
|
|
@ -751,13 +747,16 @@ include module type of Infix
|
|||
|
||||
(** {2 Pretty printing} *)
|
||||
|
||||
val pp_seq : ?sep:string -> (Format.formatter -> 'a -> unit) ->
|
||||
Format.formatter -> 'a t -> unit
|
||||
val pp_seq :
|
||||
?sep:string ->
|
||||
(Format.formatter -> 'a -> unit) ->
|
||||
Format.formatter ->
|
||||
'a t ->
|
||||
unit
|
||||
(** Pretty print an iterator of ['a], using the given pretty printer
|
||||
to print each elements. An optional separator string can be provided. *)
|
||||
|
||||
val pp_buf : ?sep:string -> (Buffer.t -> 'a -> unit) ->
|
||||
Buffer.t -> 'a t -> unit
|
||||
val pp_buf : ?sep:string -> (Buffer.t -> 'a -> unit) -> Buffer.t -> 'a t -> unit
|
||||
(** Print into a buffer *)
|
||||
|
||||
val to_string : ?sep:string -> ('a -> string) -> 'a t -> string
|
||||
|
|
@ -790,8 +789,7 @@ val to_string : ?sep:string -> ('a -> string) -> 'a t -> string
|
|||
@since 0.5.1 *)
|
||||
|
||||
module IO : sig
|
||||
val lines_of : ?mode:int -> ?flags:open_flag list ->
|
||||
string -> string t
|
||||
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
|
||||
|
|
@ -801,29 +799,29 @@ module IO : sig
|
|||
@param mode default [0o644]
|
||||
@param flags default: [[Open_rdonly]] *)
|
||||
|
||||
val chunks_of : ?mode:int -> ?flags:open_flag list -> ?size:int ->
|
||||
string -> string t
|
||||
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 iterator 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
|
||||
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_bytes_to : ?mode:int -> ?flags:open_flag list ->
|
||||
string -> Bytes.t t -> unit
|
||||
val write_bytes_to :
|
||||
?mode:int -> ?flags:open_flag list -> string -> Bytes.t t -> unit
|
||||
(** @since 0.5.4 *)
|
||||
|
||||
val write_lines : ?mode:int -> ?flags:open_flag list ->
|
||||
string -> string t -> unit
|
||||
val write_lines :
|
||||
?mode:int -> ?flags:open_flag list -> string -> string t -> unit
|
||||
(** Same as {!write_to}, but intercales ['\n'] between each string *)
|
||||
|
||||
val write_bytes_lines : ?mode:int -> ?flags:open_flag list ->
|
||||
string -> Bytes.t t -> unit
|
||||
val write_bytes_lines :
|
||||
?mode:int -> ?flags:open_flag list -> string -> Bytes.t t -> unit
|
||||
(** @since 0.5.4 *)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,91 +2,106 @@
|
|||
|
||||
module MList = struct
|
||||
type 'a t = {
|
||||
content : 'a array; (* elements of the node *)
|
||||
mutable len : int; (* number of elements in content *)
|
||||
mutable tl : 'a t; (* tail *)
|
||||
} (** A list that contains some elements, and may point to another list *)
|
||||
content: 'a array; (* elements of the node *)
|
||||
mutable len: int; (* number of elements in content *)
|
||||
mutable tl: 'a t; (* tail *)
|
||||
}
|
||||
(** A list that contains some elements, and may point to another list *)
|
||||
|
||||
let _empty () : 'a t = Obj.magic 0
|
||||
(** Empty list, for the tl field *)
|
||||
let _empty () : 'a t = Obj.magic 0
|
||||
|
||||
let make n =
|
||||
assert (n > 0);
|
||||
{ content = Array.make n (Obj.magic 0);
|
||||
len = 0;
|
||||
tl = _empty ();
|
||||
}
|
||||
{ content = Array.make n (Obj.magic 0); len = 0; tl = _empty () }
|
||||
|
||||
let rec is_empty l =
|
||||
l.len = 0 && (l.tl == _empty () || is_empty l.tl)
|
||||
let rec is_empty l = l.len = 0 && (l.tl == _empty () || is_empty l.tl)
|
||||
|
||||
let rec iter f l =
|
||||
for i = 0 to l.len - 1 do f l.content.(i); done;
|
||||
for i = 0 to l.len - 1 do
|
||||
f l.content.(i)
|
||||
done;
|
||||
if l.tl != _empty () then iter f l.tl
|
||||
|
||||
let iteri f l =
|
||||
let rec iteri i f l =
|
||||
for j = 0 to l.len - 1 do f (i+j) l.content.(j); done;
|
||||
if l.tl != _empty () then iteri (i+l.len) f l.tl
|
||||
in iteri 0 f l
|
||||
for j = 0 to l.len - 1 do
|
||||
f (i + j) l.content.(j)
|
||||
done;
|
||||
if l.tl != _empty () then iteri (i + l.len) f l.tl
|
||||
in
|
||||
iteri 0 f l
|
||||
|
||||
let rec iter_rev f l =
|
||||
(if l.tl != _empty () then iter_rev f l.tl);
|
||||
for i = l.len - 1 downto 0 do f l.content.(i); done
|
||||
if l.tl != _empty () then iter_rev f l.tl;
|
||||
for i = l.len - 1 downto 0 do
|
||||
f l.content.(i)
|
||||
done
|
||||
|
||||
let length l =
|
||||
let rec len acc l =
|
||||
if l.tl == _empty () then acc+l.len else len (acc+l.len) l.tl
|
||||
in len 0 l
|
||||
if l.tl == _empty () then
|
||||
acc + l.len
|
||||
else
|
||||
len (acc + l.len) l.tl
|
||||
in
|
||||
len 0 l
|
||||
|
||||
(** Get element by index *)
|
||||
let rec get l i =
|
||||
if i < l.len then l.content.(i)
|
||||
else if i >= l.len && l.tl == _empty () then raise (Invalid_argument "MList.get")
|
||||
else get l.tl (i - l.len)
|
||||
if i < l.len then
|
||||
l.content.(i)
|
||||
else if i >= l.len && l.tl == _empty () then
|
||||
raise (Invalid_argument "MList.get")
|
||||
else
|
||||
get l.tl (i - l.len)
|
||||
|
||||
(** Push [x] at the end of the list. It returns the block in which the
|
||||
element is inserted. *)
|
||||
let rec push x l =
|
||||
if l.len = Array.length l.content
|
||||
then begin (* insert in the next block *)
|
||||
(if l.tl == _empty () then
|
||||
if l.len = Array.length l.content then (
|
||||
(* insert in the next block *)
|
||||
if l.tl == _empty () then (
|
||||
let n = Array.length l.content in
|
||||
l.tl <- make (n + n lsr 1));
|
||||
l.tl <- make (n + (n lsr 1))
|
||||
);
|
||||
push x l.tl
|
||||
end else begin (* insert in l *)
|
||||
) else (
|
||||
(* insert in l *)
|
||||
l.content.(l.len) <- x;
|
||||
l.len <- l.len + 1;
|
||||
l
|
||||
end
|
||||
)
|
||||
|
||||
(** Reverse list (in place), and returns the new head *)
|
||||
let rev l =
|
||||
let rec rev prev l =
|
||||
(* reverse array *)
|
||||
for i = 0 to (l.len-1) / 2 do
|
||||
for i = 0 to (l.len - 1) / 2 do
|
||||
let x = l.content.(i) in
|
||||
l.content.(i) <- l.content.(l.len - i - 1);
|
||||
l.content.(l.len - i - 1) <- x;
|
||||
l.content.(l.len - i - 1) <- x
|
||||
done;
|
||||
(* reverse next block *)
|
||||
let l' = l.tl in
|
||||
l.tl <- prev;
|
||||
if l' == _empty () then l else rev l l'
|
||||
if l' == _empty () then
|
||||
l
|
||||
else
|
||||
rev l l'
|
||||
in
|
||||
rev (_empty ()) l
|
||||
|
||||
(** Build a MList of elements of the Seq. The optional argument indicates
|
||||
the size of the blocks *)
|
||||
let of_seq ?(size=8) seq =
|
||||
let of_seq ?(size = 8) seq =
|
||||
(* read iterator into a MList.t *)
|
||||
let start = make size in
|
||||
let l = ref start in
|
||||
seq (fun x -> l := push x !l);
|
||||
start
|
||||
|
||||
let to_seq l =
|
||||
fun k -> iter k l
|
||||
let to_seq l k = iter k l
|
||||
end
|
||||
|
||||
(** Store content of the seqerator in an enum *)
|
||||
|
|
@ -116,12 +131,15 @@ let bench_current n =
|
|||
let () =
|
||||
let bench_n n =
|
||||
Printf.printf "BENCH for %d\n" n;
|
||||
let res = Benchmark.throughputN 5
|
||||
[ "mlist", bench_mlist, n
|
||||
; "naive", bench_naive, n
|
||||
; "current", bench_current, n
|
||||
let res =
|
||||
Benchmark.throughputN 5
|
||||
[
|
||||
"mlist", bench_mlist, n;
|
||||
"naive", bench_naive, n;
|
||||
"current", bench_current, n;
|
||||
]
|
||||
in Benchmark.tabulate res
|
||||
in
|
||||
Benchmark.tabulate res
|
||||
in
|
||||
bench_n 100;
|
||||
bench_n 100_000;
|
||||
|
|
|
|||
|
|
@ -1,90 +1,105 @@
|
|||
module MList = struct
|
||||
type 'a t = {
|
||||
content : 'a array; (* elements of the node *)
|
||||
mutable len : int; (* number of elements in content *)
|
||||
mutable tl : 'a t; (* tail *)
|
||||
} (** A list that contains some elements, and may point to another list *)
|
||||
content: 'a array; (* elements of the node *)
|
||||
mutable len: int; (* number of elements in content *)
|
||||
mutable tl: 'a t; (* tail *)
|
||||
}
|
||||
(** A list that contains some elements, and may point to another list *)
|
||||
|
||||
let _empty () : 'a t = Obj.magic 0
|
||||
(** Empty list, for the tl field *)
|
||||
let _empty () : 'a t = Obj.magic 0
|
||||
|
||||
let make n =
|
||||
assert (n > 0);
|
||||
{ content = Array.make n (Obj.magic 0);
|
||||
len = 0;
|
||||
tl = _empty ();
|
||||
}
|
||||
{ content = Array.make n (Obj.magic 0); len = 0; tl = _empty () }
|
||||
|
||||
let rec is_empty l =
|
||||
l.len = 0 && (l.tl == _empty () || is_empty l.tl)
|
||||
let rec is_empty l = l.len = 0 && (l.tl == _empty () || is_empty l.tl)
|
||||
|
||||
let rec iter f l =
|
||||
for i = 0 to l.len - 1 do f l.content.(i); done;
|
||||
for i = 0 to l.len - 1 do
|
||||
f l.content.(i)
|
||||
done;
|
||||
if l.tl != _empty () then iter f l.tl
|
||||
|
||||
let iteri f l =
|
||||
let rec iteri i f l =
|
||||
for j = 0 to l.len - 1 do f (i+j) l.content.(j); done;
|
||||
if l.tl != _empty () then iteri (i+l.len) f l.tl
|
||||
in iteri 0 f l
|
||||
for j = 0 to l.len - 1 do
|
||||
f (i + j) l.content.(j)
|
||||
done;
|
||||
if l.tl != _empty () then iteri (i + l.len) f l.tl
|
||||
in
|
||||
iteri 0 f l
|
||||
|
||||
let rec iter_rev f l =
|
||||
(if l.tl != _empty () then iter_rev f l.tl);
|
||||
for i = l.len - 1 downto 0 do f l.content.(i); done
|
||||
if l.tl != _empty () then iter_rev f l.tl;
|
||||
for i = l.len - 1 downto 0 do
|
||||
f l.content.(i)
|
||||
done
|
||||
|
||||
let length l =
|
||||
let rec len acc l =
|
||||
if l.tl == _empty () then acc+l.len else len (acc+l.len) l.tl
|
||||
in len 0 l
|
||||
if l.tl == _empty () then
|
||||
acc + l.len
|
||||
else
|
||||
len (acc + l.len) l.tl
|
||||
in
|
||||
len 0 l
|
||||
|
||||
(** Get element by index *)
|
||||
let rec get l i =
|
||||
if i < l.len then l.content.(i)
|
||||
else if i >= l.len && l.tl == _empty () then raise (Invalid_argument "MList.get")
|
||||
else get l.tl (i - l.len)
|
||||
if i < l.len then
|
||||
l.content.(i)
|
||||
else if i >= l.len && l.tl == _empty () then
|
||||
raise (Invalid_argument "MList.get")
|
||||
else
|
||||
get l.tl (i - l.len)
|
||||
|
||||
(** Push [x] at the end of the list. It returns the block in which the
|
||||
element is inserted. *)
|
||||
let rec push x l =
|
||||
if l.len = Array.length l.content
|
||||
then begin (* insert in the next block *)
|
||||
(if l.tl == _empty () then
|
||||
if l.len = Array.length l.content then (
|
||||
(* insert in the next block *)
|
||||
if l.tl == _empty () then (
|
||||
let n = Array.length l.content in
|
||||
l.tl <- make (n + n lsr 1));
|
||||
l.tl <- make (n + (n lsr 1))
|
||||
);
|
||||
push x l.tl
|
||||
end else begin (* insert in l *)
|
||||
) else (
|
||||
(* insert in l *)
|
||||
l.content.(l.len) <- x;
|
||||
l.len <- l.len + 1;
|
||||
l
|
||||
end
|
||||
)
|
||||
|
||||
(** Reverse list (in place), and returns the new head *)
|
||||
let rev l =
|
||||
let rec rev prev l =
|
||||
(* reverse array *)
|
||||
for i = 0 to (l.len-1) / 2 do
|
||||
for i = 0 to (l.len - 1) / 2 do
|
||||
let x = l.content.(i) in
|
||||
l.content.(i) <- l.content.(l.len - i - 1);
|
||||
l.content.(l.len - i - 1) <- x;
|
||||
l.content.(l.len - i - 1) <- x
|
||||
done;
|
||||
(* reverse next block *)
|
||||
let l' = l.tl in
|
||||
l.tl <- prev;
|
||||
if l' == _empty () then l else rev l l'
|
||||
if l' == _empty () then
|
||||
l
|
||||
else
|
||||
rev l l'
|
||||
in
|
||||
rev (_empty ()) l
|
||||
|
||||
(** Build a MList of elements of the Seq. The optional argument indicates
|
||||
the size of the blocks *)
|
||||
let of_seq ?(size=8) seq =
|
||||
let of_seq ?(size = 8) seq =
|
||||
(* read iterator into a MList.t *)
|
||||
let start = make size in
|
||||
let l = ref start in
|
||||
seq (fun x -> l := push x !l);
|
||||
start
|
||||
|
||||
let to_seq l =
|
||||
fun k -> iter k l
|
||||
let to_seq l k = iter k l
|
||||
end
|
||||
|
||||
(** Store content of the seqerator in an enum *)
|
||||
|
|
@ -92,8 +107,7 @@ let persistent_mlist seq =
|
|||
let l = MList.of_seq seq in
|
||||
MList.to_seq l
|
||||
|
||||
let bench_mlist n =
|
||||
persistent_mlist Iter.(1 -- n)
|
||||
let bench_mlist n = persistent_mlist Iter.(1 -- n)
|
||||
|
||||
let bench_list n =
|
||||
let l = Iter.to_rev_list Iter.(1 -- n) in
|
||||
|
|
@ -101,18 +115,16 @@ let bench_list n =
|
|||
|
||||
let bench_naive n =
|
||||
let s = Iter.(1 -- n) in
|
||||
Iter.iter ignore s ;
|
||||
Iter.iter ignore s;
|
||||
s
|
||||
|
||||
let bench_current n =
|
||||
Iter.persistent Iter.(1 -- n)
|
||||
let bench_current n = Iter.persistent Iter.(1 -- n)
|
||||
|
||||
let bench_array n =
|
||||
let a = Iter.to_array Iter.(1 -- n) in
|
||||
Iter.of_array a
|
||||
|
||||
let read s =
|
||||
Iter.map (fun x -> x + 1) s
|
||||
let read s = Iter.map (fun x -> x + 1) s
|
||||
|
||||
let () =
|
||||
let bench_n n =
|
||||
|
|
@ -124,13 +136,15 @@ let () =
|
|||
let array = bench_current n in
|
||||
let naive = bench_naive n in
|
||||
Benchmark.throughputN 5
|
||||
[ "mlist", read, mlist
|
||||
; "list", read, list
|
||||
; "current", read, current
|
||||
; "array", read, array
|
||||
; "naive", read, naive
|
||||
[
|
||||
"mlist", read, mlist;
|
||||
"list", read, list;
|
||||
"current", read, current;
|
||||
"array", read, array;
|
||||
"naive", read, naive;
|
||||
]
|
||||
in Benchmark.tabulate res
|
||||
in
|
||||
Benchmark.tabulate res
|
||||
in
|
||||
bench_n 100;
|
||||
bench_n 100_000;
|
||||
|
|
|
|||
|
|
@ -1,36 +1,32 @@
|
|||
|
||||
module S = Iter
|
||||
open Iter.Infix
|
||||
|
||||
[@@@ocaml.warning "-5"]
|
||||
|
||||
let small = [10;20;50;100;500]
|
||||
let medium = small @ [1000;10_000;100_000]
|
||||
let big = medium @ [500_000; 1_000_000; 2_000_000]
|
||||
|
||||
let bench_fold n =
|
||||
0 -- n |> S.fold (+) 0 |> ignore
|
||||
let small = [ 10; 20; 50; 100; 500 ]
|
||||
let medium = small @ [ 1000; 10_000; 100_000 ]
|
||||
let big = medium @ [ 500_000; 1_000_000; 2_000_000 ]
|
||||
let bench_fold n = 0 -- n |> S.fold ( + ) 0 |> ignore
|
||||
|
||||
let bench_flatmap n =
|
||||
0 -- n |> S.flat_map (fun i -> i -- (i+5)) |> (fun _ -> ())
|
||||
0 -- n |> S.flat_map (fun i -> i -- (i + 5)) |> fun _ -> ()
|
||||
|
||||
let bench_product n =
|
||||
S.product (0 -- n) (0 -- n) (fun _ -> ())
|
||||
let bench_product n = S.product (0 -- n) (0 -- n) (fun _ -> ())
|
||||
|
||||
let _ =
|
||||
List.iter
|
||||
(fun (name,bench,sizes) ->
|
||||
(fun (name, bench, sizes) ->
|
||||
Format.printf "-------------------------------------------------------@.";
|
||||
Format.printf "bench %s@." name;
|
||||
List.iter
|
||||
(fun n ->
|
||||
let name = name ^ " on " ^ string_of_int n in
|
||||
let res = Benchmark.throughput1 2 ~name bench n in
|
||||
Benchmark.tabulate res;
|
||||
) sizes
|
||||
)
|
||||
[ "fold", bench_fold, big
|
||||
; "flatmap", bench_flatmap, medium
|
||||
; "product", bench_product, small
|
||||
Benchmark.tabulate res)
|
||||
sizes)
|
||||
[
|
||||
"fold", bench_fold, big;
|
||||
"flatmap", bench_flatmap, medium;
|
||||
"product", bench_product, small;
|
||||
];
|
||||
()
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
|
||||
(executables
|
||||
(names bench_persistent_read bench_persistent benchs)
|
||||
(libraries iter benchmark)
|
||||
(flags :standard -w +a-4-42-44-48-50-58-32-60@8 -safe-string -color always)
|
||||
(ocamlopt_flags :standard -O3 -color always
|
||||
-unbox-closures -unbox-closures-factor 20)
|
||||
)
|
||||
(ocamlopt_flags :standard -O3 -color always -unbox-closures
|
||||
-unbox-closures-factor 20))
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
|
||||
open Iter.Infix
|
||||
|
||||
let _ =
|
||||
let n = int_of_string Sys.argv.(1) in
|
||||
let seq = 0 -- n in
|
||||
let start = Unix.gettimeofday () in
|
||||
seq |> Iter.persistent |> Iter.fold (+) 0 |> ignore;
|
||||
seq |> Iter.persistent |> Iter.fold ( + ) 0 |> ignore;
|
||||
let stop = Unix.gettimeofday () in
|
||||
Format.printf "iter on %d: %.4f@." n (stop -. start);
|
||||
()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
(* This file is free software, part of iter. See file "license" for more details. *)
|
||||
|
||||
(** {1 Interface and Helpers for bigarrays} *)
|
||||
|
|
@ -7,13 +6,12 @@ open! IterBigarrayShims_
|
|||
|
||||
let of_bigarray b yield =
|
||||
let len = Bigarray.Array1.dim b in
|
||||
for i=0 to len-1 do
|
||||
for i = 0 to len - 1 do
|
||||
yield b.{i}
|
||||
done
|
||||
|
||||
let mmap filename =
|
||||
fun yield ->
|
||||
let fd = Unix.openfile filename [Unix.O_RDONLY] 0 in
|
||||
let mmap filename yield =
|
||||
let fd = Unix.openfile filename [ Unix.O_RDONLY ] 0 in
|
||||
let len = Unix.lseek fd 0 Unix.SEEK_END in
|
||||
let _ = Unix.lseek fd 0 Unix.SEEK_SET in
|
||||
let b = bigarray_map_file fd Bigarray.char Bigarray.c_layout false len in
|
||||
|
|
@ -23,4 +21,4 @@ let mmap filename =
|
|||
with e ->
|
||||
Unix.close fd;
|
||||
raise e
|
||||
[@@ocaml.warning "-3"]
|
||||
[@@ocaml.warning "-3"]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
|
||||
(* This file is free software, part of iter. See file "license" for more details. *)
|
||||
|
||||
(** {1 Interface and Helpers for bigarrays}
|
||||
(** Interface and Helpers for bigarrays
|
||||
|
||||
@since 0.5.4 *)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
(library
|
||||
(name iter_bigarray)
|
||||
(public_name iter.bigarray)
|
||||
|
|
@ -15,4 +14,7 @@
|
|||
(rule
|
||||
(targets IterBigarrayShims_.ml)
|
||||
(deps mkshims.exe)
|
||||
(action (with-stdout-to %{targets} (run ./mkshims.exe))))
|
||||
(action
|
||||
(with-stdout-to
|
||||
%{targets}
|
||||
(run ./mkshims.exe))))
|
||||
|
|
|
|||
|
|
@ -1,17 +1,21 @@
|
|||
|
||||
module C = Configurator.V1
|
||||
|
||||
let shims_pre_408 = "
|
||||
open! Bigarray
|
||||
let bigarray_map_file = Bigarray.Array1.map_file
|
||||
"
|
||||
let shims_post_408 = "
|
||||
let bigarray_map_file fd ty lay b len =
|
||||
Unix.map_file fd ty lay b [| len |] |> Bigarray.array1_of_genarray
|
||||
"
|
||||
let shims_pre_408 =
|
||||
"\nopen! Bigarray\nlet bigarray_map_file = Bigarray.Array1.map_file\n"
|
||||
|
||||
let shims_post_408 =
|
||||
"\n\
|
||||
let bigarray_map_file fd ty lay b len =\n\
|
||||
\ Unix.map_file fd ty lay b [| len |] |> Bigarray.array1_of_genarray\n"
|
||||
|
||||
let () =
|
||||
C.main ~name:"mkshims" (fun c ->
|
||||
let version = C.ocaml_config_var_exn c "version" in
|
||||
let major, minor = Scanf.sscanf version "%u.%u" (fun maj min -> maj, min) in
|
||||
print_endline (if (major, minor) >= (4,8) then shims_post_408 else shims_pre_408))
|
||||
let major, minor =
|
||||
Scanf.sscanf version "%u.%u" (fun maj min -> maj, min)
|
||||
in
|
||||
print_endline
|
||||
(if (major, minor) >= (4, 8) then
|
||||
shims_post_408
|
||||
else
|
||||
shims_pre_408))
|
||||
|
|
|
|||
11
src/dune
11
src/dune
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
(executable
|
||||
(name mkshims)
|
||||
(modules mkshims)
|
||||
|
|
@ -7,18 +6,20 @@
|
|||
(rule
|
||||
(targets Iter_shims_.ml)
|
||||
(deps mkshims.exe)
|
||||
(action (with-stdout-to %{targets} (run ./mkshims.exe))))
|
||||
(action
|
||||
(with-stdout-to
|
||||
%{targets}
|
||||
(run ./mkshims.exe))))
|
||||
|
||||
(library
|
||||
(name iter)
|
||||
(public_name iter)
|
||||
(wrapped false)
|
||||
(modules Iter IterLabels Iter_shims_)
|
||||
(flags :standard -nolabels)
|
||||
(flags :standard -w +a -warn-error -a+8 -nolabels)
|
||||
(libraries bytes result seq))
|
||||
|
||||
|
||||
(env
|
||||
(_
|
||||
(flags :standard -warn-error -a+8 -safe-string -strict-sequence)
|
||||
(flags :standard -w +a -warn-error -a+8 -strict-sequence)
|
||||
(ocamlopt_flags :standard -O3 -unbox-closures -unbox-closures-factor 20)))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
module C = Configurator.V1
|
||||
|
||||
let shims_pre_408 = "module Stdlib = Pervasives"
|
||||
|
|
@ -7,5 +6,11 @@ let shims_post_408 = "module Stdlib = Stdlib"
|
|||
let () =
|
||||
C.main ~name:"mkshims" (fun c ->
|
||||
let version = C.ocaml_config_var_exn c "version" in
|
||||
let major, minor = Scanf.sscanf version "%u.%u" (fun maj min -> maj, min) in
|
||||
print_endline (if (major, minor) >= (4,8) then shims_post_408 else shims_pre_408))
|
||||
let major, minor =
|
||||
Scanf.sscanf version "%u.%u" (fun maj min -> maj, min)
|
||||
in
|
||||
print_endline
|
||||
(if (major, minor) >= (4, 8) then
|
||||
shims_post_408
|
||||
else
|
||||
shims_pre_408))
|
||||
|
|
|
|||
4
tests/unit/dune
Normal file
4
tests/unit/dune
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
(tests
|
||||
(names t_iter)
|
||||
(libraries iter qcheck-core qcheck-core.runner ounit2))
|
||||
335
tests/unit/t_iter.ml
Normal file
335
tests/unit/t_iter.ml
Normal file
|
|
@ -0,0 +1,335 @@
|
|||
module Q = QCheck
|
||||
open Iter
|
||||
|
||||
let spf = Printf.sprintf
|
||||
let pp_ilist = Q.Print.(list int)
|
||||
let qchecks = ref []
|
||||
|
||||
let add_qcheck line gen prop =
|
||||
let test = Q.Test.make gen prop ~name:(spf "qcheck %d" line) in
|
||||
qchecks := test :: !qchecks
|
||||
|
||||
let () =
|
||||
let seq = empty in
|
||||
OUnit.assert_bool "empty" (is_empty seq);
|
||||
OUnit.assert_bool "empty"
|
||||
(try
|
||||
iter (fun _ -> raise Exit) seq;
|
||||
true
|
||||
with Exit -> false)
|
||||
|
||||
let () =
|
||||
let seq = repeat "hello" in
|
||||
OUnit.assert_equal [ "hello"; "hello"; "hello" ] (seq |> take 3 |> to_list)
|
||||
|
||||
let () =
|
||||
OUnit.assert_equal [ 0; 1; 2; 3; 4 ] (init (fun x -> x) |> take 5 |> to_list)
|
||||
|
||||
let () =
|
||||
let n = 1 -- 10 |> fold ( + ) 0 in
|
||||
OUnit.assert_equal 55 n;
|
||||
()
|
||||
|
||||
let () =
|
||||
let l =
|
||||
[ "hello"; "world" ] |> of_list |> foldi (fun acc i x -> (i, x) :: acc) []
|
||||
in
|
||||
OUnit.assert_equal [ 1, "world"; 0, "hello" ] l;
|
||||
()
|
||||
|
||||
let () =
|
||||
OUnit.assert_equal
|
||||
~printer:Q.Print.(list int)
|
||||
[ 0; 1; 3; 5 ]
|
||||
(0 -- 3 |> fold_map (fun prev x -> x, prev + x) 0 |> to_list)
|
||||
|
||||
let () =
|
||||
let s1 = 1 -- 5 in
|
||||
let s2 = 6 -- 10 in
|
||||
let l = [ 1; 2; 3; 4; 5; 6; 7; 8; 9; 10 ] in
|
||||
OUnit.assert_equal l (to_list (append s1 s2));
|
||||
()
|
||||
|
||||
let () =
|
||||
1 -- 1000
|
||||
|> map (fun i -> i -- (i + 1))
|
||||
|> concat |> length |> OUnit.assert_equal 2000
|
||||
|
||||
let () =
|
||||
1 -- 1000
|
||||
|> flat_map (fun i -> i -- (i + 1))
|
||||
|> length |> OUnit.assert_equal 2000
|
||||
|
||||
let test = OUnit.assert_equal ~printer:Q.Print.(list @@ list int)
|
||||
|
||||
let () =
|
||||
test
|
||||
[ [ 1; 2 ]; [ 1; 3 ] ]
|
||||
(seq_list [ singleton 1; doubleton 2 3 ] |> to_list)
|
||||
|
||||
let () = test [] (seq_list [ singleton 1; empty; doubleton 2 3 ] |> to_list)
|
||||
|
||||
let () =
|
||||
test
|
||||
[ [ 1; 2; 4 ]; [ 1; 3; 4 ] ]
|
||||
(seq_list [ singleton 1; doubleton 2 3; singleton 4 ] |> to_list)
|
||||
|
||||
let () =
|
||||
add_qcheck __LINE__
|
||||
Q.(list int)
|
||||
(fun l ->
|
||||
let seq = of_list l and f x = x mod 2 = 0 in
|
||||
filter_count f seq = (filter f seq |> length))
|
||||
|
||||
let () =
|
||||
1 -- 100
|
||||
|> (fun seq -> intersperse 0 seq)
|
||||
|> take 10 |> to_list
|
||||
|> OUnit.assert_equal [ 1; 0; 2; 0; 3; 0; 4; 0; 5; 0 ]
|
||||
|
||||
let () =
|
||||
let printer = pp_ilist in
|
||||
let iter =
|
||||
of_gen_once
|
||||
(let i = ref (-1) in
|
||||
fun () ->
|
||||
incr i;
|
||||
if !i < 5 then
|
||||
Some !i
|
||||
else
|
||||
None)
|
||||
in
|
||||
(* consume iter into a persistent version of itself *)
|
||||
let iter' = persistent iter in
|
||||
OUnit.assert_raises OneShotSequence (fun () -> iter |> to_list);
|
||||
OUnit.assert_equal ~printer [ 0; 1; 2; 3; 4 ] (iter' |> to_list);
|
||||
OUnit.assert_equal ~printer [ 0; 1; 2; 3; 4 ] (iter' |> to_list);
|
||||
OUnit.assert_equal ~printer [ 0; 1; 2; 3; 4 ]
|
||||
(iter' |> to_seq_persistent |> of_seq |> to_list);
|
||||
()
|
||||
|
||||
let () =
|
||||
let printer = pp_ilist in
|
||||
let iter = 0 -- 10_000 in
|
||||
let iter' = persistent iter in
|
||||
OUnit.assert_equal 10_001 (length iter');
|
||||
OUnit.assert_equal 10_001 (length iter');
|
||||
OUnit.assert_equal ~printer [ 0; 1; 2; 3 ] (iter' |> take 4 |> to_list);
|
||||
()
|
||||
|
||||
let () =
|
||||
1 -- 100
|
||||
|> sort ~cmp:(fun i j -> j - i)
|
||||
|> take 4 |> to_list
|
||||
|> OUnit.assert_equal [ 100; 99; 98; 97 ]
|
||||
|
||||
let test line p = OUnit.assert_bool (spf "test at %d" line) p
|
||||
let () = test __LINE__ @@ (of_list [ 1; 2; 3; 4 ] |> sorted)
|
||||
let () = test __LINE__ @@ not (of_list [ 1; 2; 3; 0; 4 ] |> sorted)
|
||||
let () = test __LINE__ @@ sorted empty
|
||||
|
||||
let () =
|
||||
[ 1; 2; 3; 3; 2; 2; 3; 4 ] |> of_list |> group_succ_by ?eq:None |> to_list
|
||||
|> OUnit.assert_equal [ [ 1 ]; [ 2 ]; [ 3; 3 ]; [ 2; 2 ]; [ 3 ]; [ 4 ] ]
|
||||
|
||||
let () =
|
||||
[ 1; 2; 3; 3; 2; 2; 3; 4 ] |> of_list
|
||||
|> group_by ?eq:None ?hash:None
|
||||
|> sort ?cmp:None |> to_list
|
||||
|> OUnit.assert_equal [ [ 1 ]; [ 2; 2; 2 ]; [ 3; 3; 3 ]; [ 4 ] ]
|
||||
|
||||
let () =
|
||||
[ 1; 2; 3; 3; 2; 2; 3; 4 ] |> of_list |> count ?eq:None ?hash:None
|
||||
|> sort ?cmp:None |> to_list
|
||||
|> OUnit.assert_equal [ 1, 1; 2, 3; 3, 3; 4, 1 ]
|
||||
|
||||
let () =
|
||||
[ 1; 2; 2; 3; 4; 4; 4; 3; 3 ]
|
||||
|> of_list |> uniq ?eq:None |> to_list
|
||||
|> OUnit.assert_equal [ 1; 2; 3; 4; 3 ]
|
||||
|
||||
let () =
|
||||
[ 42; 1; 2; 3; 4; 5; 4; 3; 2; 1 ]
|
||||
|> of_list |> sort_uniq ?cmp:None |> to_list
|
||||
|> OUnit.assert_equal [ 1; 2; 3; 4; 5; 42 ]
|
||||
|
||||
let () =
|
||||
let a = 0 -- 2 in
|
||||
let b = of_list [ "a"; "b"; "c" ] in
|
||||
let s =
|
||||
product a b |> map (fun (x, y) -> y, x) |> to_list |> List.sort compare
|
||||
in
|
||||
OUnit.assert_equal
|
||||
[ "a", 0; "a", 1; "a", 2; "b", 0; "b", 1; "b", 2; "c", 0; "c", 1; "c", 2 ]
|
||||
s
|
||||
|
||||
let () =
|
||||
OUnit.assert_equal [ 0, 1; 0, 2; 1, 2 ] (diagonal_l [ 0; 1; 2 ] |> to_list)
|
||||
|
||||
let () =
|
||||
OUnit.assert_equal
|
||||
[ 0, 1; 0, 2; 1, 2 ]
|
||||
(of_list [ 0; 1; 2 ] |> diagonal |> to_list)
|
||||
|
||||
let () =
|
||||
let s1 = 1 -- 3 in
|
||||
let s2 = of_list [ "1"; "2" ] in
|
||||
let join_row i j =
|
||||
if string_of_int i = j then
|
||||
Some (string_of_int i ^ " = " ^ j)
|
||||
else
|
||||
None
|
||||
in
|
||||
let s = join ~join_row s1 s2 in
|
||||
OUnit.assert_equal [ "1 = 1"; "2 = 2" ] (to_list s);
|
||||
()
|
||||
|
||||
let () =
|
||||
OUnit.assert_equal
|
||||
[ 'a', [ "abc"; "attic" ]; 'b', [ "barbary"; "boom"; "bop" ]; 'c', [] ]
|
||||
(group_join_by
|
||||
(fun s -> s.[0])
|
||||
(of_str "abc")
|
||||
(of_list [ "abc"; "boom"; "attic"; "deleted"; "barbary"; "bop" ])
|
||||
|> map (fun (c, l) -> c, List.sort Stdlib.compare l)
|
||||
|> sort |> to_list)
|
||||
|
||||
let () =
|
||||
let f x =
|
||||
if x < 5 then
|
||||
Some (string_of_int x, x + 1)
|
||||
else
|
||||
None
|
||||
in
|
||||
unfoldr f 0 |> to_list |> OUnit.assert_equal [ "0"; "1"; "2"; "3"; "4" ]
|
||||
|
||||
let () =
|
||||
1 -- 5 |> scan ( + ) 0 |> to_list
|
||||
|> OUnit.assert_equal ~printer:pp_ilist [ 0; 1; 3; 6; 10; 15 ]
|
||||
|
||||
let test = OUnit.assert_equal ~printer:Q.Print.int
|
||||
let () = test 100 (0 -- 100 |> max_exn ?lt:None)
|
||||
let () = test 0 (0 -- 100 |> min_exn ?lt:None)
|
||||
let () = OUnit.assert_equal 6 (of_list [ 1; 2; 3 ] |> sum)
|
||||
|
||||
let () =
|
||||
let seq = of_list [ 10000.0; 3.14159; 2.71828 ] in
|
||||
OUnit.assert_equal ~printer:string_of_float 10005.85987 (sumf seq)
|
||||
|
||||
let () =
|
||||
let l = to_list (take 0 (of_list [ 1 ])) in
|
||||
OUnit.assert_equal ~printer:pp_ilist [] l;
|
||||
let l = to_list (take 5 (of_list [ 1; 2; 3; 4; 5; 6; 7; 8; 9; 10 ])) in
|
||||
OUnit.assert_equal ~printer:pp_ilist [ 1; 2; 3; 4; 5 ] l;
|
||||
()
|
||||
|
||||
let () =
|
||||
let n =
|
||||
of_list [ true; true; false; true ]
|
||||
|> fold_while
|
||||
(fun acc b ->
|
||||
if b then
|
||||
acc + 1, `Continue
|
||||
else
|
||||
acc, `Stop)
|
||||
0
|
||||
in
|
||||
OUnit.assert_equal 2 n;
|
||||
()
|
||||
|
||||
let () = 1 -- 5 |> drop 2 |> to_list |> OUnit.assert_equal [ 3; 4; 5 ]
|
||||
let () = 1 -- 5 |> rev |> to_list |> OUnit.assert_equal [ 5; 4; 3; 2; 1 ]
|
||||
|
||||
let () =
|
||||
OUnit.assert_bool "true" (for_all (fun x -> x < 10) (1 -- 9));
|
||||
OUnit.assert_bool "false" (not (for_all (fun x -> x < 10) (2 -- 11)));
|
||||
OUnit.assert_bool "true" (for_all (fun _ -> false) empty);
|
||||
OUnit.assert_bool "nested"
|
||||
(for_all
|
||||
(fun seq -> not (for_all (fun x -> x < 8) seq))
|
||||
(1 -- 10 >|= fun x -> x -- 20));
|
||||
()
|
||||
|
||||
let () =
|
||||
1 -- 100 |> exists (fun x -> x = 59) |> OUnit.assert_bool "exists";
|
||||
1 -- 100
|
||||
|> exists (fun x -> x < 0)
|
||||
|> (fun x -> not x)
|
||||
|> OUnit.assert_bool "not exists";
|
||||
()
|
||||
|
||||
let () = 1 -- 1000 |> length |> OUnit.assert_equal 1000
|
||||
|
||||
let () =
|
||||
let h = 1 -- 5 |> zip_i |> to_hashtbl in
|
||||
0 -- 4 |> iter (fun i -> OUnit.assert_equal (i + 1) (Hashtbl.find h i));
|
||||
OUnit.assert_equal [ 0; 1; 2; 3; 4 ]
|
||||
(hashtbl_keys h |> sort ?cmp:None |> to_list);
|
||||
()
|
||||
|
||||
let () =
|
||||
let b = Buffer.create 4 in
|
||||
let upp = function
|
||||
| 'a' .. 'z' as c -> Char.chr (Char.code c - Char.code 'a' + Char.code 'A')
|
||||
| c -> c
|
||||
in
|
||||
("hello world" |> of_str |> rev |> map upp |> fun seq -> to_buffer seq b);
|
||||
OUnit.assert_equal "DLROW OLLEH" (Buffer.contents b);
|
||||
()
|
||||
|
||||
let () =
|
||||
OUnit.assert_equal ~printer:pp_ilist [ 1; 2; 3; 4 ] (to_list (1 -- 4));
|
||||
OUnit.assert_equal ~printer:pp_ilist [ 10; 9; 8; 7; 6 ] (to_list (10 --^ 6));
|
||||
OUnit.assert_equal ~printer:pp_ilist [] (to_list (10 -- 4));
|
||||
OUnit.assert_equal ~printer:pp_ilist [] (to_list (10 --^ 60));
|
||||
()
|
||||
|
||||
let test = OUnit.assert_equal ~printer:Q.Print.(list int)
|
||||
let () = test [ 1; 2; 3; 4 ] (int_range_by ~step:1 1 4 |> to_list)
|
||||
let () = test [ 4; 3; 2; 1 ] (int_range_by ~step:~-1 4 1 |> to_list)
|
||||
let () = test [ 6; 4; 2 ] (int_range_by 6 1 ~step:~-2 |> to_list)
|
||||
let () = test [] (int_range_by ~step:1 4 1 |> to_list)
|
||||
|
||||
let () =
|
||||
add_qcheck __LINE__
|
||||
Q.(pair small_int small_int)
|
||||
(fun (i, j) ->
|
||||
let i = Stdlib.min i j and j = Stdlib.max i j in
|
||||
i -- j |> to_list = (int_range_by ~step:1 i j |> to_list))
|
||||
|
||||
let () =
|
||||
add_qcheck __LINE__
|
||||
Q.(pair small_int small_int)
|
||||
(fun (i, j) ->
|
||||
let i = Stdlib.min i j and j = Stdlib.max i j in
|
||||
i -- j |> to_rev_list = (int_range_by ~step:~-1 j i |> to_list))
|
||||
|
||||
open struct
|
||||
let array_for_all f a =
|
||||
try
|
||||
for i = 0 to Array.length a - 1 do
|
||||
if not (f a.(i)) then raise Exit
|
||||
done;
|
||||
true
|
||||
with Exit -> false
|
||||
end
|
||||
|
||||
let () =
|
||||
add_qcheck __LINE__
|
||||
Q.(pair (list int) (1 -- 20))
|
||||
(fun (l, n) ->
|
||||
let seq = of_list l in
|
||||
let a = sample n seq in
|
||||
array_for_all (fun x -> exists (( = ) x) seq) a
|
||||
&& Array.length a = Stdlib.min (length seq) n)
|
||||
|
||||
(* regression tests *)
|
||||
|
||||
let () =
|
||||
let s = take 10 (repeat 1) in
|
||||
OUnit.assert_bool "not empty" (not (is_empty s));
|
||||
()
|
||||
|
||||
let () =
|
||||
let errcode = QCheck_base_runner.run_tests ~colors:false !qchecks in
|
||||
if errcode <> 0 then exit errcode
|
||||
Loading…
Add table
Reference in a new issue