mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-18 08:36:41 -05:00
Merge 1423c46b71 into 2a9795090b
This commit is contained in:
commit
e42ce3f311
22 changed files with 1401 additions and 208 deletions
8
Makefile
8
Makefile
|
|
@ -1,8 +1,10 @@
|
||||||
|
PROMOTE=$(if $(shell ocamlc -version |grep '4\.0[012]\.[0-9][0-9]*'), \
|
||||||
|
--ignore-promoted-rules, )
|
||||||
|
|
||||||
all: build test
|
all: build test
|
||||||
|
|
||||||
build:
|
build:
|
||||||
dune build @install
|
dune build $(PROMOTE) @install
|
||||||
|
|
||||||
test: build
|
test: build
|
||||||
dune runtest --no-buffer --force
|
dune runtest --no-buffer --force
|
||||||
|
|
@ -11,12 +13,12 @@ clean:
|
||||||
dune clean
|
dune clean
|
||||||
|
|
||||||
doc:
|
doc:
|
||||||
dune build @doc
|
dune build $(PROMOTE) @doc
|
||||||
|
|
||||||
BENCH_TARGETS=run_benchs.exe run_bench_hash.exe
|
BENCH_TARGETS=run_benchs.exe run_bench_hash.exe
|
||||||
|
|
||||||
benchs:
|
benchs:
|
||||||
dune build $(addprefix benchs/, $(BENCH_TARGETS))
|
dune build $(PROMOTE) $(addprefix benchs/, $(BENCH_TARGETS))
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
dune build examples/id_sexp.exe
|
dune build examples/id_sexp.exe
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ let do_not_test file =
|
||||||
is_suffix ~sub:"containers.ml" file ||
|
is_suffix ~sub:"containers.ml" file ||
|
||||||
is_suffix ~sub:"containers_top.ml" file ||
|
is_suffix ~sub:"containers_top.ml" file ||
|
||||||
is_suffix ~sub:"mkflags.ml" file ||
|
is_suffix ~sub:"mkflags.ml" file ||
|
||||||
|
is_suffix ~sub:"unlabel.ml" file ||
|
||||||
is_suffix ~sub:"utop.ml" file
|
is_suffix ~sub:"utop.ml" file
|
||||||
|
|
||||||
let prefix = "src"
|
let prefix = "src"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
(* AUTOGENERATED FROM CCArrayLabels.mli *)
|
||||||
|
|
||||||
(* This file is free software, part of containers. See file "license" for more details. *)
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
|
|
@ -13,6 +14,10 @@ type 'a printer = Format.formatter -> 'a -> unit
|
||||||
|
|
||||||
(** {2 Arrays} *)
|
(** {2 Arrays} *)
|
||||||
|
|
||||||
|
(**/**)
|
||||||
|
external make_float : int -> float array = "caml_make_float_vect" (* compat *)
|
||||||
|
(**/**)
|
||||||
|
|
||||||
include module type of Array
|
include module type of Array
|
||||||
|
|
||||||
type 'a t = 'a array
|
type 'a t = 'a array
|
||||||
|
|
@ -57,28 +62,30 @@ val length : _ t -> int
|
||||||
(** [length a] returns the length (number of elements) of the given array [a]. *)
|
(** [length a] returns the length (number of elements) of the given array [a]. *)
|
||||||
|
|
||||||
val fold : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a
|
val fold : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a
|
||||||
(** [fold f acc a] computes [f (... (f (f acc a.(0)) a.(1)) ...) a.(n-1)],
|
(** [fold f init a] computes [f (... (f (f init a.(0)) a.(1)) ...) a.(n-1)],
|
||||||
where [n] is the length of the array [a]. *)
|
where [n] is the length of the array [a]. *)
|
||||||
|
|
||||||
val foldi : ('a -> int -> 'b -> 'a) -> 'a -> 'b t -> 'a
|
val foldi : ('a -> int -> 'b -> 'a) -> 'a -> 'b t -> 'a
|
||||||
(** [foldi f acc a] is just like {!fold}, but it also passes in the index
|
(** [foldi f init a] is just like {!fold}, but it also passes in the index
|
||||||
of each element as the second argument to the folded function [f]. *)
|
of each element as the second argument to the folded function [f]. *)
|
||||||
|
|
||||||
val fold_while : ('a -> 'b -> 'a * [`Stop | `Continue]) -> 'a -> 'b t -> 'a
|
val fold_while : ('a -> 'b -> 'a * [`Stop | `Continue]) -> 'a -> 'b t -> 'a
|
||||||
(** [fold_while f acc a] folds left on array [a] until a stop condition via [('a, `Stop)]
|
(** [fold_while f init a] folds left on array [a] until a stop condition via [('a, `Stop)]
|
||||||
is indicated by the accumulator.
|
is indicated by the accumulator.
|
||||||
@since 0.8 *)
|
@since 0.8 *)
|
||||||
|
|
||||||
val fold_map : ('acc -> 'a -> 'acc * 'b) -> 'acc -> 'a t -> 'acc * 'b t
|
val fold_map : ('acc -> 'a -> 'acc * 'b) -> 'acc -> 'a t -> 'acc * 'b t
|
||||||
(** [fold_map f acc a] is a [fold_left]-like function, but it also maps the
|
(** [fold_map f init a] is a [fold_left]-like function, but it also maps the
|
||||||
array to another array.
|
array to another array.
|
||||||
@since 1.2 *)
|
@since 1.2, but only
|
||||||
|
@since 2.1 with labels *)
|
||||||
|
|
||||||
val scan_left : ('acc -> 'a -> 'acc) -> 'acc -> 'a t -> 'acc t
|
val scan_left : ('acc -> 'a -> 'acc) -> 'acc -> 'a t -> 'acc t
|
||||||
(** [scan_left f acc a] returns the array
|
(** [scan_left f init a] returns the array
|
||||||
[ [|acc; f acc x0; f (f acc a.(0)) a.(1); …|] ].
|
[ [|init; f init x0; f (f init a.(0)) a.(1); …|] ].
|
||||||
|
|
||||||
@since 1.2 *)
|
@since 1.2, but only
|
||||||
|
@since 2.1 with labels *)
|
||||||
|
|
||||||
val iter : ('a -> unit) -> 'a t -> unit
|
val iter : ('a -> unit) -> 'a t -> unit
|
||||||
(** [iter f a] applies function [f] in turn to all elements of [a].
|
(** [iter f a] applies function [f] in turn to all elements of [a].
|
||||||
|
|
@ -103,24 +110,27 @@ val reverse_in_place : 'a t -> unit
|
||||||
(** [reverse_in_place a] reverses the array [a] in place. *)
|
(** [reverse_in_place a] reverses the array [a] in place. *)
|
||||||
|
|
||||||
val sorted : ('a -> 'a -> int) -> 'a t -> 'a array
|
val sorted : ('a -> 'a -> int) -> 'a t -> 'a array
|
||||||
(** [sorted cmp a] makes a copy of [a] and sorts it with [cmp].
|
(* FIXME: better label this ~cmp ?? *)
|
||||||
|
(** [sorted f a] makes a copy of [a] and sorts it with [f].
|
||||||
@since 1.0 *)
|
@since 1.0 *)
|
||||||
|
|
||||||
val sort_indices : ('a -> 'a -> int) -> 'a t -> int array
|
val sort_indices : ('a -> 'a -> int) -> 'a t -> int array
|
||||||
(** [sort_indices cmp a] returns a new array [b], with the same length as [a],
|
(* FIXME: better label this ~cmp ?? *)
|
||||||
such that [b.(i)] is the index at which the [i]-th element of [sorted cmp a]
|
(** [sort_indices f a] returns a new array [b], with the same length as [a],
|
||||||
|
such that [b.(i)] is the index at which the [i]-th element of [sorted f a]
|
||||||
appears in [a]. [a] is not modified.
|
appears in [a]. [a] is not modified.
|
||||||
|
|
||||||
In other words, [map (fun i -> a.(i)) (sort_indices cmp a) = sorted cmp a].
|
In other words, [map (fun i -> a.(i)) (sort_indices f a) = sorted f a].
|
||||||
[sort_indices] yields the inverse permutation of {!sort_ranking}.
|
[sort_indices] yields the inverse permutation of {!sort_ranking}.
|
||||||
@since 1.0 *)
|
@since 1.0 *)
|
||||||
|
|
||||||
val sort_ranking : ('a -> 'a -> int) -> 'a t -> int array
|
val sort_ranking : ('a -> 'a -> int) -> 'a t -> int array
|
||||||
(** [sort_ranking cmp a] returns a new array [b], with the same length as [a],
|
(* FIXME: better label this ~cmp ?? *)
|
||||||
|
(** [sort_ranking f a] returns a new array [b], with the same length as [a],
|
||||||
such that [b.(i)] is the index at which the [i]-th element of [a] appears
|
such that [b.(i)] is the index at which the [i]-th element of [a] appears
|
||||||
in [sorted cmp a]. [a] is not modified.
|
in [sorted f a]. [a] is not modified.
|
||||||
|
|
||||||
In other words, [map (fun i -> (sorted cmp a).(i)) (sort_ranking cmp a) = a].
|
In other words, [map (fun i -> (sorted f a).(i)) (sort_ranking f a) = a].
|
||||||
[sort_ranking] yields the inverse permutation of {!sort_indices}.
|
[sort_ranking] yields the inverse permutation of {!sort_indices}.
|
||||||
|
|
||||||
In the absence of duplicate elements in [a], we also have
|
In the absence of duplicate elements in [a], we also have
|
||||||
|
|
@ -130,97 +140,103 @@ val sort_ranking : ('a -> 'a -> int) -> 'a t -> int array
|
||||||
val find_map : ('a -> 'b option) -> 'a t -> 'b option
|
val find_map : ('a -> 'b option) -> 'a t -> 'b option
|
||||||
(** [find_map f a] returns [Some y] if there is an element [x] such
|
(** [find_map f a] returns [Some y] if there is an element [x] such
|
||||||
that [f x = Some y]. Otherwise returns [None].
|
that [f x = Some y]. Otherwise returns [None].
|
||||||
@since 1.3 *)
|
@since 1.3, but only
|
||||||
|
@since 2.1 with labels *)
|
||||||
|
|
||||||
val find : ('a -> 'b option) -> 'a t -> 'b option
|
val find : ('a -> 'b option) -> 'a t -> 'b option
|
||||||
(** [find f a] is an alias to {!find_map}.
|
(** [find f a] is an alias to {!find_map}.
|
||||||
@deprecated since 1.3, use {!find_map} instead. *)
|
@deprecated since 1.3, use {!find_map} instead.
|
||||||
|
The version with labels is
|
||||||
|
@deprecated since 2.1, use {!find_map} instead. *)
|
||||||
|
|
||||||
val find_map_i : (int -> 'a -> 'b option) -> 'a t -> 'b option
|
val find_map_i : (int -> 'a -> 'b option) -> 'a t -> 'b option
|
||||||
(** [find_map_i f a] is like {!find_map}, but the index of the element is also passed
|
(** [find_map_i f a] is like {!find_map}, but the index of the element is also passed
|
||||||
to the predicate function [f].
|
to the predicate function [f].
|
||||||
@since 1.3 *)
|
@since 1.3, but only
|
||||||
|
@since 2.1 with labels *)
|
||||||
|
|
||||||
val findi : (int -> 'a -> 'b option) -> 'a t -> 'b option
|
val findi : (int -> 'a -> 'b option) -> 'a t -> 'b option
|
||||||
(** [findi f a] is an alias to {!find_map_i}.
|
(** [findi f a] is an alias to {!find_map_i}.
|
||||||
@since 0.3.4
|
@since 0.3.4
|
||||||
@deprecated since 1.3, use {!find_map_i} instead. *)
|
@deprecated since 1.3, use {!find_map} instead.
|
||||||
|
The version with labels is
|
||||||
|
@deprecated since 2.1, use {!find_map} instead. *)
|
||||||
|
|
||||||
val find_idx : ('a -> bool) -> 'a t -> (int * 'a) option
|
val find_idx : ('a -> bool) -> 'a t -> (int * 'a) option
|
||||||
(** [find_idx p a] returns [Some (i,x)] where [x] is the [i]-th element of [a],
|
(** [find_idx f a] returns [Some (i,x)] where [x] is the [i]-th element of [a],
|
||||||
and [p x] holds. Otherwise returns [None].
|
and [f x] holds. Otherwise returns [None].
|
||||||
@since 0.3.4 *)
|
@since 0.3.4 *)
|
||||||
|
|
||||||
val lookup : cmp:'a ord -> 'a -> 'a t -> int option
|
val lookup : cmp:'a ord -> 'a -> 'a t -> int option
|
||||||
(** [lookup cmp x a] lookups the index of some key [x] in a sorted array [a].
|
(** [lookup ~cmp key a] lookups the index of some key [key] in a sorted array [a].
|
||||||
Undefined behavior if the array [a] is not sorted wrt [cmp].
|
Undefined behavior if the array [a] is not sorted wrt [~cmp].
|
||||||
Complexity: [O(log (n))] (dichotomic search).
|
Complexity: [O(log (n))] (dichotomic search).
|
||||||
@return [None] if the key [x] is not present, or
|
@return [None] if the key [key] is not present, or
|
||||||
[Some i] ([i] the index of the key) otherwise. *)
|
[Some i] ([i] the index of the key) otherwise. *)
|
||||||
|
|
||||||
val lookup_exn : cmp:'a ord -> 'a -> 'a t -> int
|
val lookup_exn : cmp:'a ord -> 'a -> 'a t -> int
|
||||||
(** [lookup_exn cmp x a] is like {!lookup}, but
|
(** [lookup_exn ~cmp key a] is like {!lookup}, but
|
||||||
@raise Not_found if the key [x] is not present. *)
|
@raise Not_found if the key [key] is not present. *)
|
||||||
|
|
||||||
val bsearch : cmp:('a -> 'a -> int) -> 'a -> 'a t ->
|
val bsearch : cmp:('a -> 'a -> int) -> 'a -> 'a t ->
|
||||||
[ `All_lower | `All_bigger | `Just_after of int | `Empty | `At of int ]
|
[ `All_lower | `All_bigger | `Just_after of int | `Empty | `At of int ]
|
||||||
(** [bsearch ~cmp x a] finds the index of the object [x] in the array [a],
|
(** [bsearch ~cmp key a] finds the index of the object [key] in the array [a],
|
||||||
provided [a] is {b sorted} using [cmp]. If the array is not sorted,
|
provided [a] is {b sorted} using [~cmp]. If the array is not sorted,
|
||||||
the result is not specified (may raise Invalid_argument).
|
the result is not specified (may raise Invalid_argument).
|
||||||
|
|
||||||
Complexity: [O(log n)] where n is the length of the array [a]
|
Complexity: [O(log n)] where n is the length of the array [a]
|
||||||
(dichotomic search).
|
(dichotomic search).
|
||||||
|
|
||||||
@return
|
@return
|
||||||
- [`At i] if [cmp a.(i) x = 0] (for some i).
|
- [`At i] if [cmp a.(i) key = 0] (for some i).
|
||||||
- [`All_lower] if all elements of [a] are lower than [x].
|
- [`All_lower] if all elements of [a] are lower than [key].
|
||||||
- [`All_bigger] if all elements of [a] are bigger than [x].
|
- [`All_bigger] if all elements of [a] are bigger than [key].
|
||||||
- [`Just_after i] if [a.(i) < x < a.(i+1)].
|
- [`Just_after i] if [a.(i) < key < a.(i+1)].
|
||||||
- [`Empty] if the array [a] is empty.
|
- [`Empty] if the array [a] is empty.
|
||||||
|
|
||||||
@raise Invalid_argument if the array is found to be unsorted w.r.t [cmp].
|
@raise Invalid_argument if the array is found to be unsorted w.r.t [cmp].
|
||||||
@since 0.13 *)
|
@since 0.13 *)
|
||||||
|
|
||||||
val for_all : ('a -> bool) -> 'a t -> bool
|
val for_all : ('a -> bool) -> 'a t -> bool
|
||||||
(** [for_all p [|a1; ...; an|]] is [true] if all elements of the array
|
(** [for_all f [|a1; ...; an|]] is [true] if all elements of the array
|
||||||
satisfy the predicate [p]. That is, it returns
|
satisfy the predicate [f]. That is, it returns
|
||||||
[(p a1) && (p a2) && ... && (p an)]. *)
|
[(f a1) && (f a2) && ... && (f an)]. *)
|
||||||
|
|
||||||
val for_all2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool
|
val for_all2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool
|
||||||
(** [for_all2 p [|a1; ...; an|] [|b1; ...; bn|]] is [true] if each pair of elements [ai bi]
|
(** [for_all2 f [|a1; ...; an|] [|b1; ...; bn|]] is [true] if each pair of elements [ai bi]
|
||||||
satisfies the predicate [p].
|
satisfies the predicate [f].
|
||||||
That is, it returns [(p a1 b1) && (p a2 b2) && ... && (p an bn)].
|
That is, it returns [(f a1 b1) && (f a2 b2) && ... && (f an bn)].
|
||||||
|
|
||||||
@raise Invalid_argument if arrays have distinct lengths.
|
@raise Invalid_argument if arrays have distinct lengths.
|
||||||
Allow different types.
|
Allow different types.
|
||||||
@since 0.20 *)
|
@since 0.20 *)
|
||||||
|
|
||||||
val exists : ('a -> bool) -> 'a t -> bool
|
val exists : ('a -> bool) -> 'a t -> bool
|
||||||
(** [exists p [|a1; ...; an|]] is [true] if at least one element of
|
(** [exists f [|a1; ...; an|]] is [true] if at least one element of
|
||||||
the array satisfies the predicate [p]. That is, it returns
|
the array satisfies the predicate [f]. That is, it returns
|
||||||
[(p a1) || (p a2) || ... || (p an)]. *)
|
[(f a1) || (f a2) || ... || (f an)]. *)
|
||||||
|
|
||||||
val exists2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool
|
val exists2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool
|
||||||
(** [exists2 p [|a1; ...; an|] [|b1; ...; bn|]] is [true] if any pair of elements [ai bi]
|
(** [exists2 f [|a1; ...; an|] [|b1; ...; bn|]] is [true] if any pair of elements [ai bi]
|
||||||
satisfies the predicate [p].
|
satisfies the predicate [f].
|
||||||
That is, it returns [(p a1 b1) || (p a2 b2) || ... || (p an bn)].
|
That is, it returns [(f a1 b1) || (f a2 b2) || ... || (f an bn)].
|
||||||
|
|
||||||
@raise Invalid_argument if arrays have distinct lengths.
|
@raise Invalid_argument if arrays have distinct lengths.
|
||||||
Allow different types.
|
Allow different types.
|
||||||
@since 0.20 *)
|
@since 0.20 *)
|
||||||
|
|
||||||
val fold2 : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> 'a t -> 'b t -> 'acc
|
val fold2 : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> 'a t -> 'b t -> 'acc
|
||||||
(** [fold2 f acc a b] fold on two arrays [a] and [b] stepwise.
|
(** [fold2 f init a b] fold on two arrays [a] and [b] stepwise.
|
||||||
It computes [f (... (f acc a1 b1)...) an bn].
|
It computes [f (... (f init a1 b1)...) an bn].
|
||||||
|
|
||||||
@raise Invalid_argument if arrays have distinct lengths.
|
@raise Invalid_argument if [a] and [b] have distinct lengths.
|
||||||
@since 0.20 *)
|
@since 0.20 *)
|
||||||
|
|
||||||
val iter2 : ('a -> 'b -> unit) -> 'a t -> 'b t -> unit
|
val iter2 : ('a -> 'b -> unit) -> 'a t -> 'b t -> unit
|
||||||
(** [iter2 f a b] iterates on the two arrays [a] and [b] stepwise.
|
(** [iter2 f a b] iterates on the two arrays [a] and [b] stepwise.
|
||||||
It is equivalent to [f a0 b0; ...; f a.(length a - 1) b.(length b - 1); ()].
|
It is equivalent to [f a0 b0; ...; f a.(length a - 1) b.(length b - 1); ()].
|
||||||
|
|
||||||
@raise Invalid_argument if arrays have distinct lengths.
|
@raise Invalid_argument if [a] and [b] have distinct lengths.
|
||||||
@since 0.20 *)
|
@since 0.20 *)
|
||||||
|
|
||||||
val shuffle : 'a t -> unit
|
val shuffle : 'a t -> unit
|
||||||
|
|
@ -275,8 +291,8 @@ val rev : 'a t -> 'a t
|
||||||
@since 0.20 *)
|
@since 0.20 *)
|
||||||
|
|
||||||
val filter : ('a -> bool) -> 'a t -> 'a t
|
val filter : ('a -> bool) -> 'a t -> 'a t
|
||||||
(** [filter p a] filters elements out of the array [a]. Only the elements satisfying
|
(** [filter f a] filters elements out of the array [a]. Only the elements satisfying
|
||||||
the given predicate [p] will be kept. *)
|
the given predicate [f] will be kept. *)
|
||||||
|
|
||||||
val filter_map : ('a -> 'b option) -> 'a t -> 'b t
|
val filter_map : ('a -> 'b option) -> 'a t -> 'b t
|
||||||
(** [filter_map f [|a1; ...; an|]] calls [(f a1) ... (f an)] and returns an array [b] consisting
|
(** [filter_map f [|a1; ...; an|]] calls [(f a1) ... (f an)] and returns an array [b] consisting
|
||||||
|
|
@ -328,6 +344,6 @@ end
|
||||||
val sort_generic :
|
val sort_generic :
|
||||||
(module MONO_ARRAY with type t = 'arr and type elt = 'elt) ->
|
(module MONO_ARRAY with type t = 'arr and type elt = 'elt) ->
|
||||||
cmp:('elt -> 'elt -> int) -> 'arr -> unit
|
cmp:('elt -> 'elt -> int) -> 'arr -> unit
|
||||||
(** [sort_generic (module M) cmp a] sorts the array [a], without allocating (eats stack space though).
|
(** [sort_generic (module M) ~cmp a] sorts the array [a], without allocating (eats stack space though).
|
||||||
Performance might be lower than {!Array.sort}.
|
Performance might be lower than {!Array.sort}.
|
||||||
@since 0.14 *)
|
@since 0.14 *)
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,4 @@
|
||||||
|
|
||||||
(* This file is free software, part of containers. See file "license" for more details. *)
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
(* fallback function *)
|
|
||||||
external make_float : int -> float array = "caml_make_float_vect"
|
|
||||||
|
|
||||||
include CCArray
|
include CCArray
|
||||||
|
|
||||||
(*$inject
|
|
||||||
module type A = module type of CCArray
|
|
||||||
module type AL = module type of CCArrayLabels
|
|
||||||
*)
|
|
||||||
|
|
||||||
(*$R
|
|
||||||
ignore (module CCArrayLabels : A)
|
|
||||||
*)
|
|
||||||
|
|
||||||
(*$R
|
|
||||||
ignore (module CCArray : AL)
|
|
||||||
*)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,22 +75,24 @@ val fold_while : f:('a -> 'b -> 'a * [`Stop | `Continue]) -> init:'a -> 'b t ->
|
||||||
val fold_map : f:('acc -> 'a -> 'acc * 'b) -> init:'acc -> 'a t -> 'acc * 'b t
|
val fold_map : f:('acc -> 'a -> 'acc * 'b) -> init:'acc -> 'a t -> 'acc * 'b t
|
||||||
(** [fold_map ~f ~init a] is a [fold_left]-like function, but it also maps the
|
(** [fold_map ~f ~init a] is a [fold_left]-like function, but it also maps the
|
||||||
array to another array.
|
array to another array.
|
||||||
@since 2.1 *)
|
@since 1.2, but only
|
||||||
|
@since 2.1 with labels *)
|
||||||
|
|
||||||
val scan_left : f:('acc -> 'a -> 'acc) -> init:'acc -> 'a t -> 'acc t
|
val scan_left : f:('acc -> 'a -> 'acc) -> init:'acc -> 'a t -> 'acc t
|
||||||
(** [scan_left ~f ~init a] returns the array
|
(** [scan_left ~f ~init a] returns the array
|
||||||
[ [|~init; ~f ~init x0; ~f (~f ~init a.(0)) a.(1); …|] ].
|
[ [|~init; ~f ~init x0; ~f (~f ~init a.(0)) a.(1); …|] ].
|
||||||
|
|
||||||
@since 2.1 *)
|
@since 1.2, but only
|
||||||
|
@since 2.1 with labels *)
|
||||||
|
|
||||||
val iter : f:('a -> unit) -> 'a t -> unit
|
val iter : f:('a -> unit) -> 'a t -> unit
|
||||||
(** [iter ~f a] applies function [~f] in turn to all elements of [a].
|
(** [iter ~f a] applies function [~f] in turn to all elements of [a].
|
||||||
It is equivalent to [~f a.(0); ~f a.(1); ...; ~f a.(length a - 1); ()]. *)
|
It is equivalent to [~f a.(0); ~f a.(1); ...; ~f a.(length a - 1); ()]. *)
|
||||||
|
|
||||||
val iteri : f:(int -> 'a -> unit) -> 'a t -> unit
|
val iteri : f:(int -> 'a -> unit) -> 'a t -> unit
|
||||||
(** [iteri ~f a] is like {!iter}, but the function [~f] is applied with the index of the
|
(** [iteri ~f a] is like {!iter}, but the function [~f] is applied with the index of the
|
||||||
element as first argument, and the element itself as second argument. *)
|
element as first argument, and the element itself as second argument. *)
|
||||||
|
|
||||||
val blit : 'a t -> int -> 'a t -> int -> int -> unit
|
val blit : 'a t -> int -> 'a t -> int -> int -> unit
|
||||||
(** [blit a1 o1 a2 o2 len] copies [len] elements
|
(** [blit a1 o1 a2 o2 len] copies [len] elements
|
||||||
from array [a1], starting at element number [o1], to array [a2],
|
from array [a1], starting at element number [o1], to array [a2],
|
||||||
|
|
@ -106,10 +108,12 @@ val reverse_in_place : 'a t -> unit
|
||||||
(** [reverse_in_place a] reverses the array [a] in place. *)
|
(** [reverse_in_place a] reverses the array [a] in place. *)
|
||||||
|
|
||||||
val sorted : f:('a -> 'a -> int) -> 'a t -> 'a array
|
val sorted : f:('a -> 'a -> int) -> 'a t -> 'a array
|
||||||
|
(* FIXME: better label this ~cmp ?? *)
|
||||||
(** [sorted ~f a] makes a copy of [a] and sorts it with [~f].
|
(** [sorted ~f a] makes a copy of [a] and sorts it with [~f].
|
||||||
@since 1.0 *)
|
@since 1.0 *)
|
||||||
|
|
||||||
val sort_indices : f:('a -> 'a -> int) -> 'a t -> int array
|
val sort_indices : f:('a -> 'a -> int) -> 'a t -> int array
|
||||||
|
(* FIXME: better label this ~cmp ?? *)
|
||||||
(** [sort_indices ~f a] returns a new array [b], with the same length as [a],
|
(** [sort_indices ~f a] returns a new array [b], with the same length as [a],
|
||||||
such that [b.(i)] is the index at which the [i]-th element of [sorted ~f a]
|
such that [b.(i)] is the index at which the [i]-th element of [sorted ~f a]
|
||||||
appears in [a]. [a] is not modified.
|
appears in [a]. [a] is not modified.
|
||||||
|
|
@ -119,6 +123,7 @@ val sort_indices : f:('a -> 'a -> int) -> 'a t -> int array
|
||||||
@since 1.0 *)
|
@since 1.0 *)
|
||||||
|
|
||||||
val sort_ranking : f:('a -> 'a -> int) -> 'a t -> int array
|
val sort_ranking : f:('a -> 'a -> int) -> 'a t -> int array
|
||||||
|
(* FIXME: better label this ~cmp ?? *)
|
||||||
(** [sort_ranking ~f a] returns a new array [b], with the same length as [a],
|
(** [sort_ranking ~f a] returns a new array [b], with the same length as [a],
|
||||||
such that [b.(i)] is the index at which the [i]-th element of [a] appears
|
such that [b.(i)] is the index at which the [i]-th element of [a] appears
|
||||||
in [sorted ~f a]. [a] is not modified.
|
in [sorted ~f a]. [a] is not modified.
|
||||||
|
|
@ -133,39 +138,45 @@ val sort_ranking : f:('a -> 'a -> int) -> 'a t -> int array
|
||||||
val find_map : f:('a -> 'b option) -> 'a t -> 'b option
|
val find_map : f:('a -> 'b option) -> 'a t -> 'b option
|
||||||
(** [find_map ~f a] returns [Some y] if there is an element [x] such
|
(** [find_map ~f a] returns [Some y] if there is an element [x] such
|
||||||
that [~f x = Some y]. Otherwise returns [None].
|
that [~f x = Some y]. Otherwise returns [None].
|
||||||
@since 2.1 *)
|
@since 1.3, but only
|
||||||
|
@since 2.1 with labels *)
|
||||||
|
|
||||||
val find : f:('a -> 'b option) -> 'a t -> 'b option
|
val find : f:('a -> 'b option) -> 'a t -> 'b option
|
||||||
(** [find ~f a] is an alias to {!find_map}.
|
(** [find ~f a] is an alias to {!find_map}.
|
||||||
|
@deprecated since 1.3, use {!find_map} instead.
|
||||||
|
The version with labels is
|
||||||
@deprecated since 2.1, use {!find_map} instead. *)
|
@deprecated since 2.1, use {!find_map} instead. *)
|
||||||
|
|
||||||
val find_map_i : f:(int -> 'a -> 'b option) -> 'a t -> 'b option
|
val find_map_i : f:(int -> 'a -> 'b option) -> 'a t -> 'b option
|
||||||
(** [find_map_i ~f a] is like {!find_map}, but the index of the element is also passed
|
(** [find_map_i ~f a] is like {!find_map}, but the index of the element is also passed
|
||||||
to the predicate function [~f].
|
to the predicate function [~f].
|
||||||
@since 2.1 *)
|
@since 1.3, but only
|
||||||
|
@since 2.1 with labels *)
|
||||||
|
|
||||||
val findi : f:(int -> 'a -> 'b option) -> 'a t -> 'b option
|
val findi : f:(int -> 'a -> 'b option) -> 'a t -> 'b option
|
||||||
(** [findi ~f a] is an alias to {!find_map_i}.
|
(** [findi ~f a] is an alias to {!find_map_i}.
|
||||||
@since 0.3.4
|
@since 0.3.4
|
||||||
@deprecated since 2.1, use {!find_map_i} instead. *)
|
@deprecated since 1.3, use {!find_map} instead.
|
||||||
|
The version with labels is
|
||||||
|
@deprecated since 2.1, use {!find_map} instead. *)
|
||||||
|
|
||||||
val find_idx : f:('a -> bool) -> 'a t -> (int * 'a) option
|
val find_idx : f:('a -> bool) -> 'a t -> (int * 'a) option
|
||||||
(** [find_idx ~f a] returns [Some (i,x)] where [x] is the [i]-th element of [a],
|
(** [find_idx ~f a] returns [Some (i,x)] where [x] is the [i]-th element of [a],
|
||||||
and [~f x] holds. Otherwise returns [None].
|
and [~f x] holds. Otherwise returns [None].
|
||||||
@since 0.3.4 *)
|
@since 0.3.4 *)
|
||||||
|
|
||||||
val lookup : cmp:'a ord -> key:'a -> 'a t -> int option
|
val lookup : cmp:('a ord [@keep_label]) -> key:'a -> 'a t -> int option
|
||||||
(** [lookup ~cmp ~key a] lookups the index of some key [~key] in a sorted array [a].
|
(** [lookup ~cmp ~key a] lookups the index of some key [~key] in a sorted array [a].
|
||||||
Undefined behavior if the array [a] is not sorted wrt [~cmp].
|
Undefined behavior if the array [a] is not sorted wrt [~cmp].
|
||||||
Complexity: [O(log (n))] (dichotomic search).
|
Complexity: [O(log (n))] (dichotomic search).
|
||||||
@return [None] if the key [~key] is not present, or
|
@return [None] if the key [~key] is not present, or
|
||||||
[Some i] ([i] the index of the key) otherwise. *)
|
[Some i] ([i] the index of the key) otherwise. *)
|
||||||
|
|
||||||
val lookup_exn : cmp:'a ord -> key:'a -> 'a t -> int
|
val lookup_exn : cmp:('a ord [@keep_label]) -> key:'a -> 'a t -> int
|
||||||
(** [lookup_exn ~cmp ~key a] is like {!lookup}, but
|
(** [lookup_exn ~cmp ~key a] is like {!lookup}, but
|
||||||
@raise Not_found if the key [~key] is not present. *)
|
@raise Not_found if the key [~key] is not present. *)
|
||||||
|
|
||||||
val bsearch : cmp:('a -> 'a -> int) -> key:'a -> 'a t ->
|
val bsearch : cmp:(('a -> 'a -> int) [@keep_label]) -> key:'a -> 'a t ->
|
||||||
[ `All_lower | `All_bigger | `Just_after of int | `Empty | `At of int ]
|
[ `All_lower | `All_bigger | `Just_after of int | `Empty | `At of int ]
|
||||||
(** [bsearch ~cmp ~key a] finds the index of the object [~key] in the array [a],
|
(** [bsearch ~cmp ~key a] finds the index of the object [~key] in the array [a],
|
||||||
provided [a] is {b sorted} using [~cmp]. If the array is not sorted,
|
provided [a] is {b sorted} using [~cmp]. If the array is not sorted,
|
||||||
|
|
@ -270,8 +281,8 @@ val map2 : f:('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t
|
||||||
and builds an array with the results returned by [~f]:
|
and builds an array with the results returned by [~f]:
|
||||||
[[| ~f a.(0) b.(0); ...; ~f a.(length a - 1) b.(length b - 1)|]].
|
[[| ~f a.(0) b.(0); ...; ~f a.(length a - 1) b.(length b - 1)|]].
|
||||||
|
|
||||||
@raise Invalid_argument if [a] and [b] have distinct lengths.
|
@raise Invalid_argument if [a] and [b] have distinct lengths.
|
||||||
@since 0.20 *)
|
@since 0.20 *)
|
||||||
|
|
||||||
val rev : 'a t -> 'a t
|
val rev : 'a t -> 'a t
|
||||||
(** [rev a] copies the array [a] and reverses it in place.
|
(** [rev a] copies the array [a] and reverses it in place.
|
||||||
|
|
@ -330,8 +341,7 @@ end
|
||||||
|
|
||||||
val sort_generic :
|
val sort_generic :
|
||||||
(module MONO_ARRAY with type t = 'arr and type elt = 'elt) ->
|
(module MONO_ARRAY with type t = 'arr and type elt = 'elt) ->
|
||||||
cmp:('elt -> 'elt -> int) -> 'arr -> unit
|
cmp:(('elt -> 'elt -> int) [@keep_label]) -> 'arr -> unit
|
||||||
(** [sort_generic (module M) ~cmp a] sorts the array [a], without allocating (eats stack space though).
|
(** [sort_generic (module M) ~cmp a] sorts the array [a], without allocating (eats stack space though).
|
||||||
Performance might be lower than {!Array.sort}.
|
Performance might be lower than {!Array.sort}.
|
||||||
@since 0.14 *)
|
@since 0.14 *)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
(* AUTOGENERATED FROM CCArray_sliceLabels.mli *)
|
||||||
|
|
||||||
|
|
||||||
(* This file is free software, part of containers. See file "license" for more details. *)
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
|
|
@ -153,13 +155,13 @@ val find_idx : ('a -> bool) -> 'a t -> (int * 'a) option
|
||||||
and [p x] holds. Otherwise returns [None].
|
and [p x] holds. Otherwise returns [None].
|
||||||
@since 0.3.4 *)
|
@since 0.3.4 *)
|
||||||
|
|
||||||
val lookup : cmp:'a ord -> 'a -> 'a t -> int option
|
val lookup : cmp:('a ord) -> 'a -> 'a t -> int option
|
||||||
(** [lookup ~cmp x as] lookups the index [i] of some key [x] in the slice [as], provided [as] is
|
(** [lookup ~cmp x as] lookups the index [i] of some key [x] in the slice [as], provided [as] is
|
||||||
sorted using [cmp].
|
sorted using [cmp].
|
||||||
@return [None] if the key [x] is not present, or
|
@return [None] if the key [x] is not present, or
|
||||||
[Some i] ([i] the index of the key) otherwise. *)
|
[Some i] ([i] the index of the key) otherwise. *)
|
||||||
|
|
||||||
val lookup_exn : cmp:'a ord -> 'a -> 'a t -> int
|
val lookup_exn : cmp:('a ord) -> 'a -> 'a t -> int
|
||||||
(** [lookup_exn ~cmp x as] is like {!lookup}, but
|
(** [lookup_exn ~cmp x as] is like {!lookup}, but
|
||||||
@raise Not_found if the key [x] is not present. *)
|
@raise Not_found if the key [x] is not present. *)
|
||||||
|
|
||||||
|
|
|
||||||
4
src/core/CCArray_sliceLabels.ml
Normal file
4
src/core/CCArray_sliceLabels.ml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
|
include CCArray_slice
|
||||||
259
src/core/CCArray_sliceLabels.mli
Normal file
259
src/core/CCArray_sliceLabels.mli
Normal file
|
|
@ -0,0 +1,259 @@
|
||||||
|
|
||||||
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
|
(** {1 Array Slice} *)
|
||||||
|
|
||||||
|
type 'a sequence = ('a -> unit) -> unit
|
||||||
|
type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist]
|
||||||
|
type 'a gen = unit -> 'a option
|
||||||
|
type 'a equal = 'a -> 'a -> bool
|
||||||
|
type 'a ord = 'a -> 'a -> int
|
||||||
|
type 'a random_gen = Random.State.t -> 'a
|
||||||
|
type 'a printer = Format.formatter -> 'a -> unit
|
||||||
|
|
||||||
|
type 'a t
|
||||||
|
(** The type for an array slice, containing elements of type ['a] *)
|
||||||
|
|
||||||
|
val empty : 'a t
|
||||||
|
(** [empty] is the empty array slice. *)
|
||||||
|
|
||||||
|
val equal : 'a equal -> 'a t equal
|
||||||
|
(** [equal eq as1 as2] is [true] if the lengths of [as1] and [as2] are the same
|
||||||
|
and if the corresponding elements test equal using [eq]. *)
|
||||||
|
|
||||||
|
val compare : 'a ord -> 'a t ord
|
||||||
|
(** [compare cmp as1 as2] compares the two slices [as1] and [as2] using
|
||||||
|
the comparison function [cmp], element by element. *)
|
||||||
|
|
||||||
|
val get : 'a t -> int -> 'a
|
||||||
|
(** [get as n] returns the element number [n] of slice [as].
|
||||||
|
The first element has number 0.
|
||||||
|
The last element has number [length as - 1].
|
||||||
|
You can also write [as.(n)] instead of [get as n].
|
||||||
|
|
||||||
|
Raise [Invalid_argument "index out of bounds"]
|
||||||
|
if [n] is outside the range 0 to [(length as - 1)]. *)
|
||||||
|
|
||||||
|
val get_safe : 'a t -> int -> 'a option
|
||||||
|
(** [get_safe as i] returns [Some as.(i)] if [i] is a valid index.
|
||||||
|
@since 0.18 *)
|
||||||
|
|
||||||
|
val make : 'a array -> int -> len:(int [@keep_label]) -> 'a t
|
||||||
|
(** [make a i ~len] creates a slice from given offset [i] and length [len] of the given array [a].
|
||||||
|
@raise Invalid_argument if the slice isn't valid. *)
|
||||||
|
|
||||||
|
val of_slice : ('a array * int * int) -> 'a t
|
||||||
|
(** [of_slice (a, i, len)] makes a slice from a triple [(a, i, len)] where [a] is the array,
|
||||||
|
[i] the offset in [a], and [len] the number of elements of the slice.
|
||||||
|
@raise Invalid_argument if the slice isn't valid (See {!make}). *)
|
||||||
|
|
||||||
|
val to_slice : 'a t -> ('a array * int * int)
|
||||||
|
(** [to_slice as] converts the slice [as] into a triple [(a, i, len)] where [len] is the length of
|
||||||
|
the sub-array of [a] starting at offset [i]. *)
|
||||||
|
|
||||||
|
val to_list : 'a t -> 'a list
|
||||||
|
(** [to_list as] converts the slice [as] directly to a list.
|
||||||
|
@since 1.0 *)
|
||||||
|
|
||||||
|
val full : 'a array -> 'a t
|
||||||
|
(** [full a] creates a slice that covers the full array [a]. *)
|
||||||
|
|
||||||
|
val underlying : 'a t -> 'a array
|
||||||
|
(** [underlying as] returns the underlying array (shared). Modifying this array will modify
|
||||||
|
the slice [as]. *)
|
||||||
|
|
||||||
|
val copy : 'a t -> 'a array
|
||||||
|
(** [copy as] copies the slice [as] into a new array. *)
|
||||||
|
|
||||||
|
val sub : 'a t -> int -> int -> 'a t
|
||||||
|
(** [sub as i len] builds a new sub-slice that contains the given subrange specified
|
||||||
|
by the index [i] and the length [len]. *)
|
||||||
|
|
||||||
|
val set : 'a t -> int -> 'a -> unit
|
||||||
|
(** [set as n x] modifies the slice [as] in place, replacing
|
||||||
|
element number [n] with [x].
|
||||||
|
You can also write [as.(n) <- x] instead of [set as n x].
|
||||||
|
|
||||||
|
Raise [Invalid_argument "index out of bounds"]
|
||||||
|
if [n] is outside the range 0 to [length as - 1]. *)
|
||||||
|
|
||||||
|
val length : _ t -> int
|
||||||
|
(** [length as] returns the length (number of elements) of the given slice [as]. *)
|
||||||
|
|
||||||
|
val fold : ('a -> 'b -> 'a) -> 'a -> 'b t -> 'a
|
||||||
|
(** [fold f acc as] computes [f (... (f (f acc as.(0)) as.(1)) ...) as.(length as - 1)]. *)
|
||||||
|
|
||||||
|
val foldi : ('a -> int -> 'b -> 'a) -> 'a -> 'b t -> 'a
|
||||||
|
(** [foldi f acc as] is just like {!fold} but it also passes in the index of each element
|
||||||
|
as the second argument to the folded function [f]. *)
|
||||||
|
|
||||||
|
val fold_while : ('a -> 'b -> 'a * [`Stop | `Continue]) -> 'a -> 'b t -> 'a
|
||||||
|
(** [fold_while f acc as] folds left on slice [as] until a stop condition via [('a, `Stop)]
|
||||||
|
is indicated by the accumulator.
|
||||||
|
@since 0.8 *)
|
||||||
|
|
||||||
|
val iter : ('a -> unit) -> 'a t -> unit
|
||||||
|
(** [iter f as] applies function [f] in turn to all elements of [as].
|
||||||
|
It is equivalent to [f as.(0); f as.(1); ...; f as.(length as - 1); ()]. *)
|
||||||
|
|
||||||
|
val iteri : (int -> 'a -> unit) -> 'a t -> unit
|
||||||
|
(** [iteri f as] is like {!iter}, but the function [f] is applied with the index of the element
|
||||||
|
as first argument, and the element itself as second argument. *)
|
||||||
|
|
||||||
|
val blit : 'a t -> int -> 'a t -> int -> int -> unit
|
||||||
|
(** [blit as1 o1 as2 o2 len] copies [len] elements
|
||||||
|
from slice [as1], starting at element number [o1], to slice [as2],
|
||||||
|
starting at element number [o2]. It works correctly even if
|
||||||
|
[as1] and [as2] are the same slice, and the source and
|
||||||
|
destination chunks overlap.
|
||||||
|
|
||||||
|
Raise [Invalid_argument "CCArray_slice.blit"] if [o1] and [len] do not
|
||||||
|
designate a valid subarray of [as1], or if [o2] and [len] do not
|
||||||
|
designate a valid subarray of [as2]. *)
|
||||||
|
|
||||||
|
val reverse_in_place : 'a t -> unit
|
||||||
|
(** [reverse_in_place as] reverses the slice [as] in place. *)
|
||||||
|
|
||||||
|
val sorted : ('a -> 'a -> int) -> 'a t -> 'a array
|
||||||
|
(** [sorted cmp as] makes a copy of [as] and sorts it with [cmp].
|
||||||
|
@since 1.0 *)
|
||||||
|
|
||||||
|
val sort_indices : ('a -> 'a -> int) -> 'a t -> int array
|
||||||
|
(** [sort_indices cmp as] returns a new array [b], with the same length as [as],
|
||||||
|
such that [b.(i)] is the index at which the [i]-th element of [sorted cmp as]
|
||||||
|
appears in [as]. [as] is not modified.
|
||||||
|
|
||||||
|
In other words, [map (fun i -> as.(i)) (sort_indices cmp as) = sorted cmp as].
|
||||||
|
[sort_indices] yields the inverse permutation of {!sort_ranking}.
|
||||||
|
@since 1.0 *)
|
||||||
|
|
||||||
|
val sort_ranking : ('a -> 'a -> int) -> 'a t -> int array
|
||||||
|
(** [sort_ranking cmp as] returns a new array [b], with the same length as [as],
|
||||||
|
such that [b.(i)] is the index at which the [i]-th element of [as] appears
|
||||||
|
in [sorted cmp as]. [as] is not modified.
|
||||||
|
|
||||||
|
In other words, [map (fun i -> (sorted cmp as).(i)) (sort_ranking cmp as) = as].
|
||||||
|
[sort_ranking] yields the inverse permutation of {!sort_indices}.
|
||||||
|
|
||||||
|
In the absence of duplicate elements in [as], we also have
|
||||||
|
[lookup_exn as.(i) (sorted as) = (sorted_ranking as).(i)].
|
||||||
|
@since 1.0 *)
|
||||||
|
|
||||||
|
val find : ('a -> 'b option) -> 'a t -> 'b option
|
||||||
|
(** [find f as] returns [Some y] if there is an element [x] such
|
||||||
|
that [f x = Some y]. Otherwise returns [None]. *)
|
||||||
|
|
||||||
|
val findi : (int -> 'a -> 'b option) -> 'a t -> 'b option
|
||||||
|
(** [findi f as] is like {!find}, but the index of the element is also passed
|
||||||
|
to the predicate function [f].
|
||||||
|
@since 0.3.4 *)
|
||||||
|
|
||||||
|
val find_idx : ('a -> bool) -> 'a t -> (int * 'a) option
|
||||||
|
(** [find_idx p as] returns [Some (i,x)] where [x] is the [i]-th element of [as],
|
||||||
|
and [p x] holds. Otherwise returns [None].
|
||||||
|
@since 0.3.4 *)
|
||||||
|
|
||||||
|
val lookup : cmp:(('a ord) [@keep_label]) -> 'a -> 'a t -> int option
|
||||||
|
(** [lookup ~cmp x as] lookups the index [i] of some key [x] in the slice [as], provided [as] is
|
||||||
|
sorted using [cmp].
|
||||||
|
@return [None] if the key [x] is not present, or
|
||||||
|
[Some i] ([i] the index of the key) otherwise. *)
|
||||||
|
|
||||||
|
val lookup_exn : cmp:(('a ord) [@keep_label]) -> 'a -> 'a t -> int
|
||||||
|
(** [lookup_exn ~cmp x as] is like {!lookup}, but
|
||||||
|
@raise Not_found if the key [x] is not present. *)
|
||||||
|
|
||||||
|
val bsearch : cmp:(('a -> 'a -> int) [@keep_label]) -> 'a -> 'a t ->
|
||||||
|
[ `All_lower | `All_bigger | `Just_after of int | `Empty | `At of int ]
|
||||||
|
(** [bsearch ~cmp x as] finds the index of the object [x] in the slice [as],
|
||||||
|
provided [as] is {b sorted} using [cmp]. If the slice is not sorted,
|
||||||
|
the result is not specified (may raise Invalid_argument).
|
||||||
|
|
||||||
|
Complexity: [O(log n)] where n is the length of the slice [as]
|
||||||
|
(dichotomic search).
|
||||||
|
|
||||||
|
@return
|
||||||
|
- [`At i] if [cmp as.(i) x = 0] (for some i).
|
||||||
|
- [`All_lower] if all elements of [as] are lower than [x].
|
||||||
|
- [`All_bigger] if all elements of [as] are bigger than [x].
|
||||||
|
- [`Just_after i] if [as.(i) < x < as.(i+1)].
|
||||||
|
- [`Empty] if the slice [as] is empty.
|
||||||
|
|
||||||
|
@raise Invalid_argument if the slice is found to be unsorted w.r.t [cmp].
|
||||||
|
@since 0.13 *)
|
||||||
|
|
||||||
|
val for_all : ('a -> bool) -> 'a t -> bool
|
||||||
|
(** [for_all p [|as1; ...; asn|]] checks if all elements of the slice
|
||||||
|
satisfy the predicate [p]. That is, it returns
|
||||||
|
[(p as1) && (p as2) && ... && (p asn)]. *)
|
||||||
|
|
||||||
|
val for_all2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool
|
||||||
|
(** [for_all2 p [|as1; ...; asn|] [|bs1; ...; bsn|]] is [true] if each pair of elements [asi bsi]
|
||||||
|
satisfies the predicate [p].
|
||||||
|
That is, it returns [(p as1 bs1) && (p as2 bs2) && ... && (p asn bsn)].
|
||||||
|
|
||||||
|
@raise Invalid_argument if slices have distinct lengths.
|
||||||
|
Allow different types.
|
||||||
|
@since 0.20 *)
|
||||||
|
|
||||||
|
val exists : ('a -> bool) -> 'a t -> bool
|
||||||
|
(** [exists p [|as1; ...; asn|]] is [true] if at least one element of
|
||||||
|
the slice satisfies the predicate [p]. That is, it returns
|
||||||
|
[(p as1) || (p as2) || ... || (p asn)]. *)
|
||||||
|
|
||||||
|
val exists2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool
|
||||||
|
(** [exists2 p [|as1; ...; asn|] [|bs1; ...; bsn|]] is [true] if any pair of elements [asi bsi]
|
||||||
|
satisfies the predicate [p].
|
||||||
|
That is, it returns [(p as1 bs1) || (p as2 bs2) || ... || (p asn bsn)].
|
||||||
|
|
||||||
|
@raise Invalid_argument if slices have distinct lengths.
|
||||||
|
Allow different types.
|
||||||
|
@since 0.20 *)
|
||||||
|
|
||||||
|
val fold2 : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> 'a t -> 'b t -> 'acc
|
||||||
|
(** [fold2 f acc as bs] fold on two slices [as] and [bs] stepwise.
|
||||||
|
It computes [f (... (f acc as1 bs1)...) asn bsn].
|
||||||
|
|
||||||
|
@raise Invalid_argument if slices have distinct lengths.
|
||||||
|
@since 0.20 *)
|
||||||
|
|
||||||
|
val iter2 : ('a -> 'b -> unit) -> 'a t -> 'b t -> unit
|
||||||
|
(** [iter2 f as bs] iterates on the two slices [as] and [bs] stepwise.
|
||||||
|
It is equivalent to [f as0 bs0; ...; f as.(length as - 1) bs.(length bs - 1); ()].
|
||||||
|
|
||||||
|
@raise Invalid_argument if slices have distinct lengths.
|
||||||
|
@since 0.20 *)
|
||||||
|
|
||||||
|
val shuffle : 'a t -> unit
|
||||||
|
(** [shuffle as] randomly shuffles the slice [as], in place. *)
|
||||||
|
|
||||||
|
val shuffle_with : Random.State.t -> 'a t -> unit
|
||||||
|
(** [shuffle_with rs as] randomly shuffles the slice [as] (like {!shuffle}) but a specialized random
|
||||||
|
state [rs] is used to control the random numbers being produced during shuffling (for reproducibility). *)
|
||||||
|
|
||||||
|
val random_choose : 'a t -> 'a random_gen
|
||||||
|
(** [random_choose as rs] randomly chooses an element of [as].
|
||||||
|
@raise Not_found if the array/slice is empty. *)
|
||||||
|
|
||||||
|
val to_seq : 'a t -> 'a sequence
|
||||||
|
(** [to_seq as] returns a [sequence] of the elements of a slice [as].
|
||||||
|
The input slice [as] is shared with the sequence and modification of it will result
|
||||||
|
in modification of the sequence. *)
|
||||||
|
|
||||||
|
val to_gen : 'a t -> 'a gen
|
||||||
|
(** [to_gen as] returns a [gen] of the elements of a slice [as]. *)
|
||||||
|
|
||||||
|
val to_klist : 'a t -> 'a klist
|
||||||
|
(** [to_klist as] returns a [klist] of the elements of a slice [as]. *)
|
||||||
|
|
||||||
|
(** {2 IO} *)
|
||||||
|
|
||||||
|
val pp: ?sep:string -> 'a printer -> 'a t printer
|
||||||
|
(** [pp ~sep pp_item ppf as] formats the slice [as] on [ppf].
|
||||||
|
Each element is formatted with [pp_item] and elements are separated
|
||||||
|
by [sep] (defaults to ", "). *)
|
||||||
|
|
||||||
|
val pp_i: ?sep:string -> (int -> 'a printer) -> 'a t printer
|
||||||
|
(** [pp_i ~sep pp_item ppf as] prints the slice [as] on [ppf].
|
||||||
|
The printing function [pp_item] is giving both index and element.
|
||||||
|
Elements are separated by [sep] (defaults to ", "). *)
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
(* AUTOGENERATED FROM CCEqualLabels.mli *)
|
||||||
|
|
||||||
|
|
||||||
(* This file is free software, part of containers. See file "license" for more details. *)
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
|
|
|
||||||
4
src/core/CCEqualLabels.ml
Normal file
4
src/core/CCEqualLabels.ml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
|
include CCEqual
|
||||||
44
src/core/CCEqualLabels.mli
Normal file
44
src/core/CCEqualLabels.mli
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
|
||||||
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
|
(** {1 Equality Combinators} *)
|
||||||
|
|
||||||
|
(** @since 1.2 *)
|
||||||
|
|
||||||
|
type 'a t = 'a -> 'a -> bool
|
||||||
|
(** Equality function. Must be transitive, symmetric, and reflexive. *)
|
||||||
|
|
||||||
|
val poly : 'a t
|
||||||
|
(** Standard polymorphic equality. *)
|
||||||
|
|
||||||
|
val physical : 'a t
|
||||||
|
(** Standard physical equality.
|
||||||
|
@since 2.0 *)
|
||||||
|
|
||||||
|
val int : int t
|
||||||
|
val string : string t
|
||||||
|
val bool : bool t
|
||||||
|
val float : float t
|
||||||
|
val unit : unit t
|
||||||
|
|
||||||
|
val list : 'a t -> 'a list t
|
||||||
|
val array : 'a t -> 'a array t
|
||||||
|
|
||||||
|
val option : 'a t -> 'a option t
|
||||||
|
val pair : 'a t -> 'b t -> ('a * 'b) t
|
||||||
|
val triple : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t
|
||||||
|
|
||||||
|
val map : f:('a -> 'b) -> 'b t -> 'a t
|
||||||
|
(** [map f eq] is the equality function that, given objects [x] and [y],
|
||||||
|
projects [x] and [y] using [f] (e.g. using a record field) and then
|
||||||
|
compares those projections with [eq].
|
||||||
|
Example:
|
||||||
|
[map fst int] compares values of type [(int * 'a)] by their
|
||||||
|
first component. *)
|
||||||
|
|
||||||
|
module Infix : sig
|
||||||
|
val (>|=) : 'b t -> ('a -> 'b) -> 'a t
|
||||||
|
(** Infix equivalent of {!map}. *)
|
||||||
|
end
|
||||||
|
|
||||||
|
include module type of Infix
|
||||||
|
|
@ -968,7 +968,7 @@ let find_idx p l = find_mapi (fun i x -> if p x then Some (i, x) else None) l
|
||||||
find_map (fun x -> if x=3 then Some "a" else None) [1;2;4;5] = None
|
find_map (fun x -> if x=3 then Some "a" else None) [1;2;4;5] = None
|
||||||
*)
|
*)
|
||||||
|
|
||||||
let remove ~eq ~x l =
|
let remove ~eq x l =
|
||||||
let rec remove' eq x acc l = match l with
|
let rec remove' eq x acc l = match l with
|
||||||
| [] -> List.rev acc
|
| [] -> List.rev acc
|
||||||
| y :: tail when eq x y -> remove' eq x acc tail
|
| y :: tail when eq x y -> remove' eq x acc tail
|
||||||
|
|
@ -977,8 +977,8 @@ let remove ~eq ~x l =
|
||||||
remove' eq x [] l
|
remove' eq x [] l
|
||||||
|
|
||||||
(*$T
|
(*$T
|
||||||
remove ~eq:CCInt.equal ~x:1 [2;1;3;3;2;1] = [2;3;3;2]
|
remove ~eq:CCInt.equal 1 [2;1;3;3;2;1] = [2;3;3;2]
|
||||||
remove ~eq:CCInt.equal ~x:10 [1;2;3] = [1;2;3]
|
remove ~eq:CCInt.equal 10 [1;2;3] = [1;2;3]
|
||||||
*)
|
*)
|
||||||
|
|
||||||
let filter_map f l =
|
let filter_map f l =
|
||||||
|
|
@ -1483,7 +1483,7 @@ module Assoc = struct
|
||||||
not (Assoc.mem ~eq:CCInt.equal 4 [1,"1"; 2,"2"; 3, "3"])
|
not (Assoc.mem ~eq:CCInt.equal 4 [1,"1"; 2,"2"; 3, "3"])
|
||||||
*)
|
*)
|
||||||
|
|
||||||
let update ~eq ~f x l =
|
let update ~eq f x l =
|
||||||
search_set eq [] l x
|
search_set eq [] l x
|
||||||
~f:(fun x opt_y rest ->
|
~f:(fun x opt_y rest ->
|
||||||
match f opt_y with
|
match f opt_y with
|
||||||
|
|
@ -1492,13 +1492,13 @@ module Assoc = struct
|
||||||
(*$=
|
(*$=
|
||||||
[1,"1"; 2,"22"] \
|
[1,"1"; 2,"22"] \
|
||||||
(Assoc.update ~eq:CCInt.equal \
|
(Assoc.update ~eq:CCInt.equal \
|
||||||
~f:(function Some "2" -> Some "22" | _ -> assert false) 2 [1,"1"; 2,"2"] |> lsort)
|
(function Some "2" -> Some "22" | _ -> assert false) 2 [1,"1"; 2,"2"] |> lsort)
|
||||||
[1,"1"; 3,"3"] \
|
[1,"1"; 3,"3"] \
|
||||||
(Assoc.update ~eq:CCInt.equal \
|
(Assoc.update ~eq:CCInt.equal \
|
||||||
~f:(function Some "2" -> None | _ -> assert false) 2 [1,"1"; 2,"2"; 3,"3"] |> lsort)
|
(function Some "2" -> None | _ -> assert false) 2 [1,"1"; 2,"2"; 3,"3"] |> lsort)
|
||||||
[1,"1"; 2,"2"; 3,"3"] \
|
[1,"1"; 2,"2"; 3,"3"] \
|
||||||
(Assoc.update ~eq:CCInt.equal \
|
(Assoc.update ~eq:CCInt.equal \
|
||||||
~f:(function None -> Some "3" | _ -> assert false) 3 [1,"1"; 2,"2"] |> lsort)
|
(function None -> Some "3" | _ -> assert false) 3 [1,"1"; 2,"2"] |> lsort)
|
||||||
*)
|
*)
|
||||||
|
|
||||||
let remove ~eq x l =
|
let remove ~eq x l =
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
(* AUTOGENERATED FROM CCListLabels.mli *)
|
||||||
|
|
||||||
|
|
||||||
(* This file is free software, part of containers. See file "license" for more details. *)
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
|
|
@ -61,14 +63,15 @@ val fold_while : ('a -> 'b -> 'a * [`Stop | `Continue]) -> 'a -> 'b t -> 'a
|
||||||
@since 0.8 *)
|
@since 0.8 *)
|
||||||
|
|
||||||
val fold_map : ('acc -> 'a -> 'acc * 'b) -> 'acc -> 'a list -> 'acc * 'b list
|
val fold_map : ('acc -> 'a -> 'acc * 'b) -> 'acc -> 'a list -> 'acc * 'b list
|
||||||
(** [fold_map f acc l] is a [fold_left]-like function, but it also maps the
|
(** [fold_map f init l] is a [fold_left]-like function, but it also maps the
|
||||||
list to another list.
|
list to another list.
|
||||||
@since 0.14 *)
|
@since 0.14 *)
|
||||||
|
|
||||||
val scan_left : ('acc -> 'a -> 'acc) -> 'acc -> 'a list -> 'acc list
|
val scan_left : ('acc -> 'a -> 'acc) -> 'acc -> 'a list -> 'acc list
|
||||||
(** [scan_left f acc l] returns the list [[acc; f acc x0; f (f acc x0) x1; ...]]
|
(** [scan_left f init l] returns the list [[init; f init x0; f (f init x0) x1; ...]]
|
||||||
where [x0], [x1], etc. are the elements of [l].
|
where [x0], [x1], etc. are the elements of [l].
|
||||||
@since 1.2 *)
|
@since 1.2, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val fold_map2 : ('acc -> 'a -> 'b -> 'acc * 'c) -> 'acc -> 'a list -> 'b list -> 'acc * 'c list
|
val fold_map2 : ('acc -> 'a -> 'b -> 'acc * 'c) -> 'acc -> 'a list -> 'b list -> 'acc * 'c list
|
||||||
(** [fold_map2] is to [fold_map] what [List.map2] is to [List.map].
|
(** [fold_map2] is to [fold_map] what [List.map2] is to [List.map].
|
||||||
|
|
@ -76,7 +79,7 @@ val fold_map2 : ('acc -> 'a -> 'b -> 'acc * 'c) -> 'acc -> 'a list -> 'b list ->
|
||||||
@since 0.16 *)
|
@since 0.16 *)
|
||||||
|
|
||||||
val fold_filter_map : ('acc -> 'a -> 'acc * 'b option) -> 'acc -> 'a list -> 'acc * 'b list
|
val fold_filter_map : ('acc -> 'a -> 'acc * 'b option) -> 'acc -> 'a list -> 'acc * 'b list
|
||||||
(** [fold_filter_map f acc l] is a [fold_left]-like function, but also
|
(** [fold_filter_map f init l] is a [fold_left]-like function, but also
|
||||||
generates a list of output in a way similar to {!filter_map}.
|
generates a list of output in a way similar to {!filter_map}.
|
||||||
@since 0.17 *)
|
@since 0.17 *)
|
||||||
|
|
||||||
|
|
@ -87,12 +90,11 @@ val fold_flat_map : ('acc -> 'a -> 'acc * 'b list) -> 'acc -> 'a list -> 'acc *
|
||||||
|
|
||||||
val count : ('a -> bool) -> 'a list -> int
|
val count : ('a -> bool) -> 'a list -> int
|
||||||
(** [count p l] counts how many elements of [l] satisfy predicate [p].
|
(** [count p l] counts how many elements of [l] satisfy predicate [p].
|
||||||
@since 1.5 *)
|
@since 1.5, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val count_true_false : ('a -> bool) -> 'a list -> int * int
|
val count_true_false : ('a -> bool) -> 'a list -> int * int
|
||||||
(** [let ok_count, ko_count = count_true_false p l in ...]
|
(** @since NEXT_RELEASE *)
|
||||||
count_true_false how many elements of [l] satisfy (resp. violate) predicate [p].
|
|
||||||
@since NEXT_RELEASE *)
|
|
||||||
|
|
||||||
val init : int -> (int -> 'a) -> 'a t
|
val init : int -> (int -> 'a) -> 'a t
|
||||||
(** [init len f] is [f 0; f 1; ...; f (len-1)].
|
(** [init len f] is [f 0; f 1; ...; f (len-1)].
|
||||||
|
|
@ -105,31 +107,37 @@ val combine : 'a list -> 'b list -> ('a * 'b) list
|
||||||
[combine [a1; ...; an] [b1; ...; bn]] is
|
[combine [a1; ...; an] [b1; ...; bn]] is
|
||||||
[[(a1,b1); ...; (an,bn)]].
|
[[(a1,b1); ...; (an,bn)]].
|
||||||
@raise Invalid_argument if the lists have distinct lengths.
|
@raise Invalid_argument if the lists have distinct lengths.
|
||||||
@since 1.2 *)
|
@since 1.2, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val combine_gen : 'a list -> 'b list -> ('a * 'b) gen
|
val combine_gen : 'a list -> 'b list -> ('a * 'b) gen
|
||||||
(** Lazy version of {!combine}.
|
(** Lazy version of {!combine}.
|
||||||
Unlike {!combine}, it does not fail if the lists have different
|
Unlike {!combine}, it does not fail if the lists have different
|
||||||
lengths;
|
lengths;
|
||||||
instead, the output has as many pairs as the smallest input list.
|
instead, the output has as many pairs as the smallest input list.
|
||||||
@since 1.2 *)
|
@since 1.2, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val split : ('a * 'b) t -> 'a t * 'b t
|
val split : ('a * 'b) t -> 'a t * 'b t
|
||||||
(** A tail-recursive version of {!List.split}.
|
(** A tail-recursive version of {!List.split}.
|
||||||
Transform a list of pairs into a pair of lists:
|
Transform a list of pairs into a pair of lists:
|
||||||
[split [(a1,b1); ...; (an,bn)]] is [([a1; ...; an], [b1; ...; bn])]. *)
|
[split [(a1,b1); ...; (an,bn)]] is [([a1; ...; an], [b1; ...; bn])].
|
||||||
|
@since 1.2, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int
|
val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int
|
||||||
|
|
||||||
val compare_lengths : 'a t -> 'b t -> int
|
val compare_lengths : 'a t -> 'b t -> int
|
||||||
(** Equivalent to [compare (length l1) (length l2)] but more efficient.
|
(** Equivalent to [compare (length l1) (length l2)] but more efficient.
|
||||||
Compare the lengths of two lists.
|
Compare the lengths of two lists.
|
||||||
@since 1.5 *)
|
@since 1.5, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val compare_length_with : 'a t -> int -> int
|
val compare_length_with : 'a t -> int -> int
|
||||||
(** Equivalent to [compare (length l) x] but more efficient.
|
(** Equivalent to [compare (length l) x] but more efficient.
|
||||||
Compare the length of a list to an integer.
|
Compare the length of a list to an integer.
|
||||||
@since 1.5 *)
|
@since 1.5, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
|
val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
|
||||||
|
|
||||||
|
|
@ -158,14 +166,16 @@ val cartesian_product : 'a t t -> 'a t t
|
||||||
[[1;3;4;5;6];[2;3;4;5;6]];;
|
[[1;3;4;5;6];[2;3;4;5;6]];;
|
||||||
]}
|
]}
|
||||||
invariant: [cartesian_product l = map_product id l].
|
invariant: [cartesian_product l = map_product id l].
|
||||||
@since 1.2 *)
|
@since 1.2, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val map_product_l : ('a -> 'b list) -> 'a list -> 'b list list
|
val map_product_l : ('a -> 'b list) -> 'a list -> 'b list list
|
||||||
(** [map_product_l f l] maps each element of [l] to a list of
|
(** [map_product_l f l] maps each element of [l] to a list of
|
||||||
objects of type ['b] using [f].
|
objects of type ['b] using [f].
|
||||||
We obtain [[l1;l2;...;ln]] where [length l=n] and [li : 'b list].
|
We obtain [[l1;l2;...;ln]] where [length l=n] and [li : 'b list].
|
||||||
Then, it returns all the ways of picking exactly one element per [li].
|
Then, it returns all the ways of picking exactly one element per [li].
|
||||||
@since 1.2 *)
|
@since 1.2, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val diagonal : 'a t -> ('a * 'a) t
|
val diagonal : 'a t -> ('a * 'a) t
|
||||||
(** All pairs of distinct positions of the list. [list_diagonal l] will
|
(** All pairs of distinct positions of the list. [list_diagonal l] will
|
||||||
|
|
@ -263,16 +273,21 @@ val sublists_of_len :
|
||||||
If [last = CCOpt.return], it will simply keep the last group.
|
If [last = CCOpt.return], it will simply keep the last group.
|
||||||
By default, [last = fun _ -> None], i.e. the last group is dropped if shorter than [n].
|
By default, [last = fun _ -> None], i.e. the last group is dropped if shorter than [n].
|
||||||
@raise Invalid_argument if [offset <= 0] or [n <= 0].
|
@raise Invalid_argument if [offset <= 0] or [n <= 0].
|
||||||
@since 1.0 *)
|
See {!CCList.sublists_of_len} for more details.
|
||||||
|
|
||||||
|
@since 1.0, but only
|
||||||
|
@since 1.5 with labels *)
|
||||||
|
|
||||||
val intersperse : 'a -> 'a list -> 'a list
|
val intersperse : 'a -> 'a list -> 'a list
|
||||||
(** Insert the first argument between every element of the list.
|
(** Insert the first argument between every element of the list.
|
||||||
@since 2.1 *)
|
@since 2.1, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val interleave : 'a list -> 'a list -> 'a list
|
val interleave : 'a list -> 'a list -> 'a list
|
||||||
(** [interleave [x1…xn] [y1…ym]] is [x1,y1,x2,y2,…] and finishes with
|
(** [interleave [x1…xn] [y1…ym]] is [x1,y1,x2,y2,…] and finishes with
|
||||||
the suffix of the longest list.
|
the suffix of the longest list.
|
||||||
@since 2.1 *)
|
@since 2.1, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val pure : 'a -> 'a t
|
val pure : 'a -> 'a t
|
||||||
(** [pure] is [return]. *)
|
(** [pure] is [return]. *)
|
||||||
|
|
@ -281,7 +296,7 @@ val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
|
||||||
(** [funs <*> l] is [product (fun f x -> f x) funs l]. *)
|
(** [funs <*> l] is [product (fun f x -> f x) funs l]. *)
|
||||||
|
|
||||||
val (<$>) : ('a -> 'b) -> 'a t -> 'b t
|
val (<$>) : ('a -> 'b) -> 'a t -> 'b t
|
||||||
(** [(<$>)] = [map]. *)
|
(** [(<$>)] is [map]. *)
|
||||||
|
|
||||||
val return : 'a -> 'a t
|
val return : 'a -> 'a t
|
||||||
(** [return x] is [x]. *)
|
(** [return x] is [x]. *)
|
||||||
|
|
@ -314,7 +329,8 @@ val drop_while : ('a -> bool) -> 'a t -> 'a t
|
||||||
|
|
||||||
val take_drop_while : ('a -> bool) -> 'a t -> 'a t * 'a t
|
val take_drop_while : ('a -> bool) -> 'a t -> 'a t * 'a t
|
||||||
(** [take_drop_while p l] = [take_while p l, drop_while p l].
|
(** [take_drop_while p l] = [take_while p l, drop_while p l].
|
||||||
@since 1.2 *)
|
@since 1.2, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val last : int -> 'a t -> 'a t
|
val last : int -> 'a t -> 'a t
|
||||||
(** [last n l] takes the last [n] elements of [l] (or less if
|
(** [last n l] takes the last [n] elements of [l] (or less if
|
||||||
|
|
@ -339,7 +355,8 @@ val find_pred : ('a -> bool) -> 'a t -> 'a option
|
||||||
|
|
||||||
val find_opt : ('a -> bool) -> 'a t -> 'a option
|
val find_opt : ('a -> bool) -> 'a t -> 'a option
|
||||||
(** Safe version of {!find}.
|
(** Safe version of {!find}.
|
||||||
@since 1.5 *)
|
@since 1.5, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val find_pred_exn : ('a -> bool) -> 'a t -> 'a
|
val find_pred_exn : ('a -> bool) -> 'a t -> 'a
|
||||||
(** Unsafe version of {!find_pred}.
|
(** Unsafe version of {!find_pred}.
|
||||||
|
|
@ -360,8 +377,9 @@ val find_idx : ('a -> bool) -> 'a t -> (int * 'a) option
|
||||||
(** [find_idx p x] returns [Some (i,x)] where [x] is the [i]-th element of [l],
|
(** [find_idx p x] returns [Some (i,x)] where [x] is the [i]-th element of [l],
|
||||||
and [p x] holds. Otherwise returns [None]. *)
|
and [p x] holds. Otherwise returns [None]. *)
|
||||||
|
|
||||||
val remove : eq:('a -> 'a -> bool) -> x:'a -> 'a t -> 'a t
|
val remove : eq:('a -> 'a -> bool) -> 'a -> 'a t -> 'a t
|
||||||
(** [remove ~x l] removes every instance of [x] from [l]. Tail-recursive.
|
(* FIXME: the original CCList.mli uses ~x instead of ~key !! *)
|
||||||
|
(** [remove key l] removes every instance of [key] from [l]. Tail-recursive.
|
||||||
@param eq equality function.
|
@param eq equality function.
|
||||||
@since 0.11 *)
|
@since 0.11 *)
|
||||||
|
|
||||||
|
|
@ -373,21 +391,25 @@ val filter_map : ('a -> 'b option) -> 'a t -> 'b t
|
||||||
val keep_some : 'a option t -> 'a t
|
val keep_some : 'a option t -> 'a t
|
||||||
(** [keep_some l] retains only elements of the form [Some x].
|
(** [keep_some l] retains only elements of the form [Some x].
|
||||||
Like [filter_map CCFun.id].
|
Like [filter_map CCFun.id].
|
||||||
@since 1.3 *)
|
@since 1.3, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val keep_ok : ('a, _) Result.result t -> 'a t
|
val keep_ok : ('a, _) Result.result t -> 'a t
|
||||||
(** [keep_ok l] retains only elements of the form [Ok x].
|
(** [keep_ok l] retains only elements of the form [Ok x].
|
||||||
@since 1.3 *)
|
@since 1.3, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val all_some : 'a option t -> 'a t option
|
val all_some : 'a option t -> 'a t option
|
||||||
(** [all_some l] returns [Some l'] if all elements of [l] are of the form [Some x],
|
(** [all_some l] returns [Some l'] if all elements of [l] are of the form [Some x],
|
||||||
or [None] otherwise.
|
or [None] otherwise.
|
||||||
@since 1.3 *)
|
@since 1.3, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val all_ok : ('a, 'err) Result.result t -> ('a t, 'err) Result.result
|
val all_ok : ('a, 'err) Result.result t -> ('a t, 'err) Result.result
|
||||||
(** [all_ok l] returns [Ok l'] if all elements of [l] are of the form [Ok x],
|
(** [all_ok l] returns [Ok l'] if all elements of [l] are of the form [Ok x],
|
||||||
or [Error e] otherwise (with the first error met).
|
or [Error e] otherwise (with the first error met).
|
||||||
@since 1.3 *)
|
@since 1.3, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val sorted_merge : cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list
|
val sorted_merge : cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list
|
||||||
(** Merge elements from both sorted list. *)
|
(** Merge elements from both sorted list. *)
|
||||||
|
|
@ -439,7 +461,8 @@ val iteri : (int -> 'a -> unit) -> 'a t -> unit
|
||||||
val iteri2 : (int -> 'a -> 'b -> unit) -> 'a t -> 'b t -> unit
|
val iteri2 : (int -> 'a -> 'b -> unit) -> 'a t -> 'b t -> unit
|
||||||
(** Iter on two lists.
|
(** Iter on two lists.
|
||||||
@raise Invalid_argument when lists do not have the same length.
|
@raise Invalid_argument when lists do not have the same length.
|
||||||
@since 2.0 *)
|
@since 2.0, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val foldi : ('b -> int -> 'a -> 'b) -> 'b -> 'a t -> 'b
|
val foldi : ('b -> int -> 'a -> 'b) -> 'b -> 'a t -> 'b
|
||||||
(** Like [fold] but it also passes in the index of each element to the folded function. Tail-recursive. *)
|
(** Like [fold] but it also passes in the index of each element to the folded function. Tail-recursive. *)
|
||||||
|
|
@ -447,7 +470,8 @@ val foldi : ('b -> int -> 'a -> 'b) -> 'b -> 'a t -> 'b
|
||||||
val foldi2 : ('c -> int -> 'a -> 'b -> 'c) -> 'c -> 'a t -> 'b t -> 'c
|
val foldi2 : ('c -> int -> 'a -> 'b -> 'c) -> 'c -> 'a t -> 'b t -> 'c
|
||||||
(** Fold on two lists, with index.
|
(** Fold on two lists, with index.
|
||||||
@raise Invalid_argument when lists do not have the same length.
|
@raise Invalid_argument when lists do not have the same length.
|
||||||
@since 2.0 *)
|
@since 2.0, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val get_at_idx : int -> 'a t -> 'a option
|
val get_at_idx : int -> 'a t -> 'a option
|
||||||
(** Get by index in the list.
|
(** Get by index in the list.
|
||||||
|
|
@ -457,7 +481,8 @@ val get_at_idx : int -> 'a t -> 'a option
|
||||||
val nth_opt : 'a t -> int -> 'a option
|
val nth_opt : 'a t -> int -> 'a option
|
||||||
(** Safe version of {!nth}.
|
(** Safe version of {!nth}.
|
||||||
@raise Invalid_argument if the int is negative.
|
@raise Invalid_argument if the int is negative.
|
||||||
@since 1.5 *)
|
@since 1.5, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val get_at_idx_exn : int -> 'a t -> 'a
|
val get_at_idx_exn : int -> 'a t -> 'a
|
||||||
(** Get the i-th element, or
|
(** Get the i-th element, or
|
||||||
|
|
@ -564,8 +589,9 @@ module Assoc : sig
|
||||||
@since 0.16 *)
|
@since 0.16 *)
|
||||||
|
|
||||||
val update :
|
val update :
|
||||||
eq:('a->'a->bool) -> f:('b option -> 'b option) -> 'a -> ('a,'b) t -> ('a,'b) t
|
eq:('a->'a->bool) -> ('b option -> 'b option) -> 'a -> ('a,'b) t -> ('a,'b) t
|
||||||
(** [update k ~f l] updates [l] on the key [k], by calling [f (get l k)]
|
(* FIXME: the original no labels mli kept the ~f label ! *)
|
||||||
|
(** [update k f l] updates [l] on the key [k], by calling [f (get l k)]
|
||||||
and removing [k] if it returns [None], mapping [k] to [v'] if it
|
and removing [k] if it returns [None], mapping [k] to [v'] if it
|
||||||
returns [Some v'].
|
returns [Some v'].
|
||||||
@since 0.16 *)
|
@since 0.16 *)
|
||||||
|
|
@ -581,11 +607,13 @@ val assoc : eq:('a -> 'a -> bool) -> 'a -> ('a * 'b) t -> 'b
|
||||||
|
|
||||||
val assoc_opt : eq:('a -> 'a -> bool) -> 'a -> ('a * 'b) t -> 'b option
|
val assoc_opt : eq:('a -> 'a -> bool) -> 'a -> ('a * 'b) t -> 'b option
|
||||||
(** Like [Assoc.get].
|
(** Like [Assoc.get].
|
||||||
@since 1.5 *)
|
@since 1.5, but only
|
||||||
|
@since 2.0 with labels *)
|
||||||
|
|
||||||
val assq_opt : 'a -> ('a * 'b) t -> 'b option
|
val assq_opt : 'a -> ('a * 'b) t -> 'b option
|
||||||
(** Safe version of {!assq}.
|
(** Safe version of {!assq}.
|
||||||
@since 1.5 *)
|
@since 1.5, but only
|
||||||
|
@since 2.0 with labels *)
|
||||||
|
|
||||||
val mem_assoc : eq:('a -> 'a -> bool) -> 'a -> ('a * _) t -> bool
|
val mem_assoc : eq:('a -> 'a -> bool) -> 'a -> ('a * _) t -> bool
|
||||||
(** Like [Assoc.mem].
|
(** Like [Assoc.mem].
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,3 @@
|
||||||
(* This file is free software, part of containers. See file "license" for more details. *)
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
include CCList
|
include CCList
|
||||||
|
|
||||||
(*$inject
|
|
||||||
module type L = module type of CCList
|
|
||||||
module type LL = module type of CCListLabels
|
|
||||||
*)
|
|
||||||
|
|
||||||
(*$R
|
|
||||||
ignore (module CCListLabels : L)
|
|
||||||
*)
|
|
||||||
|
|
||||||
(*$R
|
|
||||||
ignore (module CCList : LL)
|
|
||||||
*)
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,10 @@ val fold_map : f:('acc -> 'a -> 'acc * 'b) -> init:'acc -> 'a list -> 'acc * 'b
|
||||||
@since 0.14 *)
|
@since 0.14 *)
|
||||||
|
|
||||||
val scan_left : f:('acc -> 'a -> 'acc) -> init:'acc -> 'a list -> 'acc list
|
val scan_left : f:('acc -> 'a -> 'acc) -> init:'acc -> 'a list -> 'acc list
|
||||||
(** @since 2.2 *)
|
(** [scan_left ~f ~init l] returns the list [[init; f init x0; f (f init x0) x1; ...]]
|
||||||
|
where [x0], [x1], etc. are the elements of [l].
|
||||||
|
@since 1.2, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val fold_map2 : f:('acc -> 'a -> 'b -> 'acc * 'c) -> init:'acc -> 'a list -> 'b list -> 'acc * 'c list
|
val fold_map2 : f:('acc -> 'a -> 'b -> 'acc * 'c) -> init:'acc -> 'a list -> 'b list -> 'acc * 'c list
|
||||||
(** [fold_map2] is to [fold_map] what [List.map2] is to [List.map].
|
(** [fold_map2] is to [fold_map] what [List.map2] is to [List.map].
|
||||||
|
|
@ -84,7 +87,9 @@ val fold_flat_map : f:('acc -> 'a -> 'acc * 'b list) -> init:'acc -> 'a list ->
|
||||||
@since 0.14 *)
|
@since 0.14 *)
|
||||||
|
|
||||||
val count : f:('a -> bool) -> 'a list -> int
|
val count : f:('a -> bool) -> 'a list -> int
|
||||||
(** @since 2.2 *)
|
(** [count p l] counts how many elements of [l] satisfy predicate [p].
|
||||||
|
@since 1.5, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val count_true_false : f:('a -> bool) -> 'a list -> int * int
|
val count_true_false : f:('a -> bool) -> 'a list -> int * int
|
||||||
(** @since NEXT_RELEASE *)
|
(** @since NEXT_RELEASE *)
|
||||||
|
|
@ -95,21 +100,42 @@ val init : int -> f:(int -> 'a) -> 'a t
|
||||||
@since 0.6 *)
|
@since 0.6 *)
|
||||||
|
|
||||||
val combine : 'a list -> 'b list -> ('a * 'b) list
|
val combine : 'a list -> 'b list -> ('a * 'b) list
|
||||||
(** @since 2.2 *)
|
(** Like {!List.combine} but tail-recursive.
|
||||||
|
Transform a pair of lists into a list of pairs:
|
||||||
|
[combine [a1; ...; an] [b1; ...; bn]] is
|
||||||
|
[[(a1,b1); ...; (an,bn)]].
|
||||||
|
@raise Invalid_argument if the lists have distinct lengths.
|
||||||
|
@since 1.2, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val combine_gen : 'a list -> 'b list -> ('a * 'b) gen
|
val combine_gen : 'a list -> 'b list -> ('a * 'b) gen
|
||||||
(** @since 2.2 *)
|
(** Lazy version of {!combine}.
|
||||||
|
Unlike {!combine}, it does not fail if the lists have different
|
||||||
|
lengths;
|
||||||
|
instead, the output has as many pairs as the smallest input list.
|
||||||
|
@since 1.2, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val split : ('a * 'b) t -> 'a t * 'b t
|
val split : ('a * 'b) t -> 'a t * 'b t
|
||||||
(** @since 2.2 *)
|
(** A tail-recursive version of {!List.split}.
|
||||||
|
Transform a list of pairs into a pair of lists:
|
||||||
|
[split [(a1,b1); ...; (an,bn)]] is [([a1; ...; an], [b1; ...; bn])].
|
||||||
|
@since 1.2, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int
|
val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int
|
||||||
|
|
||||||
val compare_lengths : 'a t -> 'b t -> int
|
val compare_lengths : 'a t -> 'b t -> int
|
||||||
(** @since 2.2 *)
|
(** Equivalent to [compare (length l1) (length l2)] but more efficient.
|
||||||
|
Compare the lengths of two lists.
|
||||||
|
@since 1.5, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val compare_length_with : 'a t -> int -> int
|
val compare_length_with : 'a t -> int -> int
|
||||||
(** @since 2.2 *)
|
(** Equivalent to [compare (length l) x] but more efficient.
|
||||||
|
Compare the length of a list to an integer.
|
||||||
|
@since 1.5, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
|
val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
|
||||||
|
|
||||||
|
|
@ -126,10 +152,28 @@ val fold_product : f:('c -> 'a -> 'b -> 'c) -> init:'c -> 'a t -> 'b t -> 'c
|
||||||
(** Fold on the cartesian product. *)
|
(** Fold on the cartesian product. *)
|
||||||
|
|
||||||
val cartesian_product : 'a t t -> 'a t t
|
val cartesian_product : 'a t t -> 'a t t
|
||||||
(** @since 2.2 *)
|
(** Produce the cartesian product of this list of lists,
|
||||||
|
by returning all the ways of picking one element per sublist.
|
||||||
|
{b NOTE} the order of the returned list is unspecified.
|
||||||
|
For example:
|
||||||
|
{[
|
||||||
|
# cartesian_product [[1;2];[3];[4;5;6]] |> sort =
|
||||||
|
[[1;3;4];[1;3;5];[1;3;6];[2;3;4];[2;3;5];[2;3;6]];;
|
||||||
|
# cartesian_product [[1;2];[];[4;5;6]] = [];;
|
||||||
|
# cartesian_product [[1;2];[3];[4];[5];[6]] |> sort =
|
||||||
|
[[1;3;4;5;6];[2;3;4;5;6]];;
|
||||||
|
]}
|
||||||
|
invariant: [cartesian_product l = map_product id l].
|
||||||
|
@since 1.2, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val map_product_l : f:('a -> 'b list) -> 'a list -> 'b list list
|
val map_product_l : f:('a -> 'b list) -> 'a list -> 'b list list
|
||||||
(** @since 2.2 *)
|
(** [map_product_l f l] maps each element of [l] to a list of
|
||||||
|
objects of type ['b] using [f].
|
||||||
|
We obtain [[l1;l2;...;ln]] where [length l=n] and [li : 'b list].
|
||||||
|
Then, it returns all the ways of picking exactly one element per [li].
|
||||||
|
@since 1.2, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val diagonal : 'a t -> ('a * 'a) t
|
val diagonal : 'a t -> ('a * 'a) t
|
||||||
(** All pairs of distinct positions of the list. [list_diagonal l] will
|
(** All pairs of distinct positions of the list. [list_diagonal l] will
|
||||||
|
|
@ -149,7 +193,7 @@ val group_by : ?hash:('a -> int) -> ?eq:('a -> 'a -> bool) ->
|
||||||
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
||||||
@since 2.3 *)
|
@since 2.3 *)
|
||||||
|
|
||||||
val join : join_row:('a -> 'b -> 'c option) -> 'a t -> 'b t -> 'c t
|
val join : join_row:(('a -> 'b -> 'c option) [@keep_label]) -> 'a t -> 'b t -> 'c t
|
||||||
(** [join ~join_row a b] combines every element of [a] with every
|
(** [join ~join_row a b] combines every element of [a] with every
|
||||||
element of [b] using [join_row]. If [join_row] returns None, then
|
element of [b] using [join_row]. If [join_row] returns None, then
|
||||||
the two elements do not combine. Assume that [b] allows for multiple
|
the two elements do not combine. Assume that [b] allows for multiple
|
||||||
|
|
@ -158,7 +202,7 @@ val join : join_row:('a -> 'b -> 'c option) -> 'a t -> 'b t -> 'c t
|
||||||
|
|
||||||
val join_by : ?eq:('key -> 'key -> bool) -> ?hash:('key -> int) ->
|
val join_by : ?eq:('key -> 'key -> bool) -> ?hash:('key -> int) ->
|
||||||
('a -> 'key) -> ('b -> 'key) ->
|
('a -> 'key) -> ('b -> 'key) ->
|
||||||
merge:('key -> 'a -> 'b -> 'c option) ->
|
merge:(('key -> 'a -> 'b -> 'c option) [@keep_label]) ->
|
||||||
'a t ->
|
'a t ->
|
||||||
'b t ->
|
'b t ->
|
||||||
'c t
|
'c t
|
||||||
|
|
@ -173,7 +217,7 @@ val join_by : ?eq:('key -> 'key -> bool) -> ?hash:('key -> int) ->
|
||||||
|
|
||||||
val join_all_by : ?eq:('key -> 'key -> bool) -> ?hash:('key -> int) ->
|
val join_all_by : ?eq:('key -> 'key -> bool) -> ?hash:('key -> int) ->
|
||||||
('a -> 'key) -> ('b -> 'key) ->
|
('a -> 'key) -> ('b -> 'key) ->
|
||||||
merge:('key -> 'a list -> 'b list -> 'c option) ->
|
merge:(('key -> 'a list -> 'b list -> 'c option) [@keep_label]) ->
|
||||||
'a t ->
|
'a t ->
|
||||||
'b t ->
|
'b t ->
|
||||||
'c t
|
'c t
|
||||||
|
|
@ -201,7 +245,6 @@ val group_join_by : ?eq:('a -> 'a -> bool) -> ?hash:('a -> int) ->
|
||||||
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
precondition: for any [x] and [y], if [eq x y] then [hash x=hash y] must hold.
|
||||||
@since 2.3 *)
|
@since 2.3 *)
|
||||||
|
|
||||||
|
|
||||||
val sublists_of_len :
|
val sublists_of_len :
|
||||||
?last:('a list -> 'a list option) ->
|
?last:('a list -> 'a list option) ->
|
||||||
?offset:int ->
|
?offset:int ->
|
||||||
|
|
@ -212,24 +255,43 @@ val sublists_of_len :
|
||||||
By default, these sub-lists are non overlapping:
|
By default, these sub-lists are non overlapping:
|
||||||
[sublists_of_len 2 [1;2;3;4;5;6]] returns [[1;2]; [3;4]; [5;6]].
|
[sublists_of_len 2 [1;2;3;4;5;6]] returns [[1;2]; [3;4]; [5;6]].
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- [sublists_of_len 2 [1;2;3;4;5;6] = [[1;2]; [3;4]; [5;6]]].
|
||||||
|
- [sublists_of_len 2 ~offset:3 [1;2;3;4;5;6] = [1;2];[4;5]].
|
||||||
|
- [sublists_of_len 3 ~last:CCOpt.return [1;2;3;4] = [1;2;3];[4]].
|
||||||
|
- [sublists_of_len 2 [1;2;3;4;5] = [[1;2]; [3;4]]].
|
||||||
|
|
||||||
|
@param offset the number of elements skipped between two consecutive
|
||||||
|
sub-lists. By default it is [n]. If [offset < n], the sub-lists
|
||||||
|
will overlap; if [offset > n], some elements will not appear at all.
|
||||||
|
@param last if provided and the last group of elements [g] is such
|
||||||
|
that [length g < n], [last g] is called. If [last g = Some g'],
|
||||||
|
[g'] is appended; otherwise [g] is dropped.
|
||||||
|
If [last = CCOpt.return], it will simply keep the last group.
|
||||||
|
By default, [last = fun _ -> None], i.e. the last group is dropped if shorter than [n].
|
||||||
|
@raise Invalid_argument if [offset <= 0] or [n <= 0].
|
||||||
See {!CCList.sublists_of_len} for more details.
|
See {!CCList.sublists_of_len} for more details.
|
||||||
|
|
||||||
@since 1.5 *)
|
@since 1.0, but only
|
||||||
|
@since 1.5 with labels *)
|
||||||
|
|
||||||
val intersperse : x:'a -> 'a list -> 'a list
|
val intersperse : x:'a -> 'a list -> 'a list
|
||||||
(** Insert the first argument between every element of the list.
|
(** Insert the first argument between every element of the list.
|
||||||
@since 2.2 *)
|
@since 2.1, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val interleave : 'a list -> 'a list -> 'a list
|
val interleave : 'a list -> 'a list -> 'a list
|
||||||
(** [interleave [x1…xn] [y1…ym]] is [x1,y1,x2,y2,…] and finishes with
|
(** [interleave [x1…xn] [y1…ym]] is [x1,y1,x2,y2,…] and finishes with
|
||||||
the suffix of the longest list.
|
the suffix of the longest list.
|
||||||
@since 2.2 *)
|
@since 2.1, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val pure : 'a -> 'a t
|
val pure : 'a -> 'a t
|
||||||
(** [pure] is [return]. *)
|
(** [pure] is [return]. *)
|
||||||
|
|
||||||
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
|
val (<*>) : ('a -> 'b) t -> 'a t -> 'b t
|
||||||
(** [funs <*> l] is [product fun f x -> f x) funs l]. *)
|
(** [funs <*> l] is [product (fun f x -> f x) funs l]. *)
|
||||||
|
|
||||||
val (<$>) : ('a -> 'b) -> 'a t -> 'b t
|
val (<$>) : ('a -> 'b) -> 'a t -> 'b t
|
||||||
(** [(<$>)] is [map]. *)
|
(** [(<$>)] is [map]. *)
|
||||||
|
|
@ -264,7 +326,9 @@ val drop_while : f:('a -> bool) -> 'a t -> 'a t
|
||||||
@since 0.13 *)
|
@since 0.13 *)
|
||||||
|
|
||||||
val take_drop_while : f:('a -> bool) -> 'a t -> 'a t * 'a t
|
val take_drop_while : f:('a -> bool) -> 'a t -> 'a t * 'a t
|
||||||
(** @since 2.2 *)
|
(** [take_drop_while p l] = [take_while p l, drop_while p l].
|
||||||
|
@since 1.2, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val last : int -> 'a t -> 'a t
|
val last : int -> 'a t -> 'a t
|
||||||
(** [last n l] takes the last [n] elements of [l] (or less if
|
(** [last n l] takes the last [n] elements of [l] (or less if
|
||||||
|
|
@ -288,7 +352,9 @@ val find_pred : f:('a -> bool) -> 'a t -> 'a option
|
||||||
@since 0.11 *)
|
@since 0.11 *)
|
||||||
|
|
||||||
val find_opt : f:('a -> bool) -> 'a t -> 'a option
|
val find_opt : f:('a -> bool) -> 'a t -> 'a option
|
||||||
(** @since 2.2 *)
|
(** Safe version of {!find}.
|
||||||
|
@since 1.5, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val find_pred_exn : f:('a -> bool) -> 'a t -> 'a
|
val find_pred_exn : f:('a -> bool) -> 'a t -> 'a
|
||||||
(** Unsafe version of {!find_pred}.
|
(** Unsafe version of {!find_pred}.
|
||||||
|
|
@ -309,7 +375,8 @@ val find_idx : f:('a -> bool) -> 'a t -> (int * 'a) option
|
||||||
(** [find_idx p x] returns [Some (i,x)] where [x] is the [i]-th element of [l],
|
(** [find_idx p x] returns [Some (i,x)] where [x] is the [i]-th element of [l],
|
||||||
and [p x] holds. Otherwise returns [None]. *)
|
and [p x] holds. Otherwise returns [None]. *)
|
||||||
|
|
||||||
val remove : eq:('a -> 'a -> bool) -> key:'a -> 'a t -> 'a t
|
val remove : eq:(('a -> 'a -> bool) [@keep_label]) -> key:'a -> 'a t -> 'a t
|
||||||
|
(* FIXME: the original CCList.mli uses ~x instead of ~key !! *)
|
||||||
(** [remove ~key l] removes every instance of [key] from [l]. Tail-recursive.
|
(** [remove ~key l] removes every instance of [key] from [l]. Tail-recursive.
|
||||||
@param eq equality function.
|
@param eq equality function.
|
||||||
@since 0.11 *)
|
@since 0.11 *)
|
||||||
|
|
@ -320,48 +387,59 @@ val filter_map : f:('a -> 'b option) -> 'a t -> 'b t
|
||||||
Map and remove elements at the same time. *)
|
Map and remove elements at the same time. *)
|
||||||
|
|
||||||
val keep_some : 'a option t -> 'a t
|
val keep_some : 'a option t -> 'a t
|
||||||
(** @since 2.2 *)
|
(** [keep_some l] retains only elements of the form [Some x].
|
||||||
|
Like [filter_map CCFun.id].
|
||||||
|
@since 1.3, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val keep_ok : ('a, _) Result.result t -> 'a t
|
val keep_ok : ('a, _) Result.result t -> 'a t
|
||||||
(** @since 2.2 *)
|
(** [keep_ok l] retains only elements of the form [Ok x].
|
||||||
|
@since 1.3, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val all_some : 'a option t -> 'a t option
|
val all_some : 'a option t -> 'a t option
|
||||||
(** @since 2.2 *)
|
(** [all_some l] returns [Some l'] if all elements of [l] are of the form [Some x],
|
||||||
|
or [None] otherwise.
|
||||||
|
@since 1.3, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val all_ok : ('a, 'err) Result.result t -> ('a t, 'err) Result.result
|
val all_ok : ('a, 'err) Result.result t -> ('a t, 'err) Result.result
|
||||||
(** @since 2.2 *)
|
(** [all_ok l] returns [Ok l'] if all elements of [l] are of the form [Ok x],
|
||||||
|
or [Error e] otherwise (with the first error met).
|
||||||
|
@since 1.3, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val sorted_merge : cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list
|
val sorted_merge : cmp:(('a -> 'a -> int) [@keep_label]) -> 'a list -> 'a list -> 'a list
|
||||||
(** Merges elements from both sorted list. *)
|
(** Merge elements from both sorted list. *)
|
||||||
|
|
||||||
val sort_uniq : cmp:('a -> 'a -> int) -> 'a list -> 'a list
|
val sort_uniq : cmp:(('a -> 'a -> int) [@keep_label]) -> 'a list -> 'a list
|
||||||
(** Sort the list and remove duplicate elements. *)
|
(** Sort the list and remove duplicate elements. *)
|
||||||
|
|
||||||
val sorted_merge_uniq : cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list
|
val sorted_merge_uniq : cmp:(('a -> 'a -> int) [@keep_label]) -> 'a list -> 'a list -> 'a list
|
||||||
(** [sorted_merge_uniq l1 l2] merges the sorted lists [l1] and [l2] and
|
(** [sorted_merge_uniq l1 l2] merges the sorted lists [l1] and [l2] and
|
||||||
removes duplicates.
|
removes duplicates.
|
||||||
@since 0.10 *)
|
@since 0.10 *)
|
||||||
|
|
||||||
val is_sorted : cmp:('a -> 'a -> int) -> 'a list -> bool
|
val is_sorted : cmp:(('a -> 'a -> int) [@keep_label]) -> 'a list -> bool
|
||||||
(** [is_sorted l] returns [true] iff [l] is sorted (according to given order).
|
(** [is_sorted l] returns [true] iff [l] is sorted (according to given order).
|
||||||
@param cmp the comparison function (default [Pervasives.compare]).
|
@param cmp the comparison function (default [Pervasives.compare]).
|
||||||
@since 0.17 *)
|
@since 0.17 *)
|
||||||
|
|
||||||
val sorted_insert : cmp:('a -> 'a -> int) -> ?uniq:bool -> 'a -> 'a list -> 'a list
|
val sorted_insert : cmp:(('a -> 'a -> int) [@keep_label]) -> ?uniq:bool -> 'a -> 'a list -> 'a list
|
||||||
(** [sorted_insert x l] inserts [x] into [l] such that, if [l] was sorted,
|
(** [sorted_insert x l] inserts [x] into [l] such that, if [l] was sorted,
|
||||||
then [sorted_insert x l] is sorted too.
|
then [sorted_insert x l] is sorted too.
|
||||||
@param uniq if true and [x] is already in sorted position in [l], then
|
@param uniq if true and [x] is already in sorted position in [l], then
|
||||||
[x] is not duplicated. Default [false] ([x] will be inserted in any case).
|
[x] is not duplicated. Default [false] ([x] will be inserted in any case).
|
||||||
@since 0.17 *)
|
@since 0.17 *)
|
||||||
|
|
||||||
val uniq_succ : eq:('a -> 'a -> bool) -> 'a list -> 'a list
|
val uniq_succ : eq:(('a -> 'a -> bool) [@keep_label]) -> 'a list -> 'a list
|
||||||
(** [uniq_succ l] removes duplicate elements that occur one next to the other.
|
(** [uniq_succ l] removes duplicate elements that occur one next to the other.
|
||||||
Examples:
|
Examples:
|
||||||
[uniq_succ [1;2;1] = [1;2;1]].
|
[uniq_succ [1;2;1] = [1;2;1]].
|
||||||
[uniq_succ [1;1;2] = [1;2]].
|
[uniq_succ [1;1;2] = [1;2]].
|
||||||
@since 0.10 *)
|
@since 0.10 *)
|
||||||
|
|
||||||
val group_succ : eq:('a -> 'a -> bool) -> 'a list -> 'a list list
|
val group_succ : eq:(('a -> 'a -> bool) [@keep_label]) -> 'a list -> 'a list list
|
||||||
(** [group_succ ~eq l] groups together consecutive elements that are equal
|
(** [group_succ ~eq l] groups together consecutive elements that are equal
|
||||||
according to [eq].
|
according to [eq].
|
||||||
@since 0.11 *)
|
@since 0.11 *)
|
||||||
|
|
@ -379,13 +457,19 @@ val iteri : f:(int -> 'a -> unit) -> 'a t -> unit
|
||||||
itself as second argument. *)
|
itself as second argument. *)
|
||||||
|
|
||||||
val iteri2 : f:(int -> 'a -> 'b -> unit) -> 'a t -> 'b t -> unit
|
val iteri2 : f:(int -> 'a -> 'b -> unit) -> 'a t -> 'b t -> unit
|
||||||
(** @since 2.2 *)
|
(** Iter on two lists.
|
||||||
|
@raise Invalid_argument when lists do not have the same length.
|
||||||
|
@since 2.0, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val foldi : f:('b -> int -> 'a -> 'b) -> init:'b -> 'a t -> 'b
|
val foldi : f:('b -> int -> 'a -> 'b) -> init:'b -> 'a t -> 'b
|
||||||
(** Like [fold] but it also passes in the index of each element to the folded function. Tail-recursive. *)
|
(** Like [fold] but it also passes in the index of each element to the folded function. Tail-recursive. *)
|
||||||
|
|
||||||
val foldi2 : f:('c -> int -> 'a -> 'b -> 'c) -> init:'c -> 'a t -> 'b t -> 'c
|
val foldi2 : f:('c -> int -> 'a -> 'b -> 'c) -> init:'c -> 'a t -> 'b t -> 'c
|
||||||
(** @since 2.2 *)
|
(** Fold on two lists, with index.
|
||||||
|
@raise Invalid_argument when lists do not have the same length.
|
||||||
|
@since 2.0, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val get_at_idx : int -> 'a t -> 'a option
|
val get_at_idx : int -> 'a t -> 'a option
|
||||||
(** Get by index in the list.
|
(** Get by index in the list.
|
||||||
|
|
@ -393,7 +477,10 @@ val get_at_idx : int -> 'a t -> 'a option
|
||||||
of the list. *)
|
of the list. *)
|
||||||
|
|
||||||
val nth_opt : 'a t -> int -> 'a option
|
val nth_opt : 'a t -> int -> 'a option
|
||||||
(** @since 2.2 *)
|
(** Safe version of {!nth}.
|
||||||
|
@raise Invalid_argument if the int is negative.
|
||||||
|
@since 1.5, but only
|
||||||
|
@since 2.2 with labels *)
|
||||||
|
|
||||||
val get_at_idx_exn : int -> 'a t -> 'a
|
val get_at_idx_exn : int -> 'a t -> 'a
|
||||||
(** Get the i-th element, or
|
(** Get the i-th element, or
|
||||||
|
|
@ -424,38 +511,38 @@ val remove_at_idx : int -> 'a t -> 'a t
|
||||||
Those operations maintain the invariant that the list does not
|
Those operations maintain the invariant that the list does not
|
||||||
contain duplicates (if it already satisfies it). *)
|
contain duplicates (if it already satisfies it). *)
|
||||||
|
|
||||||
val add_nodup : eq:('a -> 'a -> bool) -> 'a -> 'a t -> 'a t
|
val add_nodup : eq:(('a -> 'a -> bool) [@keep_label]) -> 'a -> 'a t -> 'a t
|
||||||
(** [add_nodup x set] adds [x] to [set] if it was not already present. Linear time.
|
(** [add_nodup x set] adds [x] to [set] if it was not already present. Linear time.
|
||||||
@since 0.11 *)
|
@since 0.11 *)
|
||||||
|
|
||||||
val remove_one : eq:('a -> 'a -> bool) -> 'a -> 'a t -> 'a t
|
val remove_one : eq:(('a -> 'a -> bool) [@keep_label]) -> 'a -> 'a t -> 'a t
|
||||||
(** [remove_one x set] removes one occurrence of [x] from [set]. Linear time.
|
(** [remove_one x set] removes one occurrence of [x] from [set]. Linear time.
|
||||||
@since 0.11 *)
|
@since 0.11 *)
|
||||||
|
|
||||||
val mem : eq:('a -> 'a -> bool) -> 'a -> 'a t -> bool
|
val mem : eq:(('a -> 'a -> bool) [@keep_label]) -> 'a -> 'a t -> bool
|
||||||
(** Membership to the list. Linear time. *)
|
(** Membership to the list. Linear time. *)
|
||||||
|
|
||||||
val subset : eq:('a -> 'a -> bool) -> 'a t -> 'a t -> bool
|
val subset : eq:(('a -> 'a -> bool) [@keep_label]) -> 'a t -> 'a t -> bool
|
||||||
(** Test for inclusion. *)
|
(** Test for inclusion. *)
|
||||||
|
|
||||||
val uniq : eq:('a -> 'a -> bool) -> 'a t -> 'a t
|
val uniq : eq:(('a -> 'a -> bool) [@keep_label]) -> 'a t -> 'a t
|
||||||
(** Remove duplicates w.r.t the equality predicate.
|
(** Remove duplicates w.r.t the equality predicate.
|
||||||
Complexity is quadratic in the length of the list, but the order
|
Complexity is quadratic in the length of the list, but the order
|
||||||
of elements is preserved. If you wish for a faster de-duplication
|
of elements is preserved. If you wish for a faster de-duplication
|
||||||
but do not care about the order, use {!sort_uniq}. *)
|
but do not care about the order, use {!sort_uniq}. *)
|
||||||
|
|
||||||
val union : eq:('a -> 'a -> bool) -> 'a t -> 'a t -> 'a t
|
val union : eq:(('a -> 'a -> bool) [@keep_label]) -> 'a t -> 'a t -> 'a t
|
||||||
(** List union. Complexity is product of length of inputs. *)
|
(** List union. Complexity is product of length of inputs. *)
|
||||||
|
|
||||||
val inter : eq:('a -> 'a -> bool) -> 'a t -> 'a t -> 'a t
|
val inter : eq:(('a -> 'a -> bool) [@keep_label]) -> 'a t -> 'a t -> 'a t
|
||||||
(** List intersection. Complexity is product of length of inputs. *)
|
(** List intersection. Complexity is product of length of inputs. *)
|
||||||
|
|
||||||
(** {2 Other Constructors} *)
|
(** {2 Other Constructors} *)
|
||||||
|
|
||||||
val range_by : step:int -> int -> int -> int t
|
val range_by : step:(int [@keep_label]) -> int -> int -> int t
|
||||||
(** [range_by ~step i j] iterates on integers from [i] to [j] included,
|
(** [range_by ~step i j] iterates on integers from [i] to [j] included,
|
||||||
where the difference between successive elements is [step].
|
where the difference between successive elements is [step].
|
||||||
use a negative [step] for a decreasing list.
|
Use a negative [step] for a decreasing list.
|
||||||
@raise Invalid_argument if [step=0].
|
@raise Invalid_argument if [step=0].
|
||||||
@since 0.18 *)
|
@since 0.18 *)
|
||||||
|
|
||||||
|
|
@ -485,49 +572,52 @@ val repeat : int -> 'a t -> 'a t
|
||||||
module Assoc : sig
|
module Assoc : sig
|
||||||
type ('a, 'b) t = ('a*'b) list
|
type ('a, 'b) t = ('a*'b) list
|
||||||
|
|
||||||
val get : eq:('a->'a->bool) -> 'a -> ('a,'b) t -> 'b option
|
val get : eq:(('a->'a->bool) [@keep_label]) -> 'a -> ('a,'b) t -> 'b option
|
||||||
(** Find the element. *)
|
(** Find the element. *)
|
||||||
|
|
||||||
val get_exn : eq:('a->'a->bool) -> 'a -> ('a,'b) t -> 'b
|
val get_exn : eq:(('a->'a->bool) [@keep_label]) -> 'a -> ('a,'b) t -> 'b
|
||||||
(** Like [get], but unsafe.
|
(** Like [get], but unsafe.
|
||||||
@raise Not_found if the element is not present. *)
|
@raise Not_found if the element is not present. *)
|
||||||
|
|
||||||
val set : eq:('a->'a->bool) -> 'a -> 'b -> ('a,'b) t -> ('a,'b) t
|
val set : eq:(('a->'a->bool) [@keep_label]) -> 'a -> 'b -> ('a,'b) t -> ('a,'b) t
|
||||||
(** Add the binding into the list (erase it if already present). *)
|
(** Add the binding into the list (erase it if already present). *)
|
||||||
|
|
||||||
val mem : eq:('a->'a->bool) -> 'a -> ('a,_) t -> bool
|
val mem : eq:(('a->'a->bool) [@keep_label]) -> 'a -> ('a,_) t -> bool
|
||||||
(** [mem x l] returns [true] iff [x] is a key in [l].
|
(** [mem x l] returns [true] iff [x] is a key in [l].
|
||||||
@since 0.16 *)
|
@since 0.16 *)
|
||||||
|
|
||||||
val update :
|
val update :
|
||||||
eq:('a->'a->bool) -> f:('b option -> 'b option) -> 'a -> ('a,'b) t -> ('a,'b) t
|
eq:(('a->'a->bool) [@keep_label]) -> f:('b option -> 'b option) -> 'a -> ('a,'b) t -> ('a,'b) t
|
||||||
|
(* FIXME: the original no labels mli kept the ~f label ! *)
|
||||||
(** [update k ~f l] updates [l] on the key [k], by calling [f (get l k)]
|
(** [update k ~f l] updates [l] on the key [k], by calling [f (get l k)]
|
||||||
and removing [k] if it returns [None], mapping [k] to [v'] if it
|
and removing [k] if it returns [None], mapping [k] to [v'] if it
|
||||||
returns [Some v'].
|
returns [Some v'].
|
||||||
@since 0.16 *)
|
@since 0.16 *)
|
||||||
|
|
||||||
val remove : eq:('a->'a->bool) -> 'a -> ('a,'b) t -> ('a,'b) t
|
val remove : eq:(('a->'a->bool) [@keep_label]) -> 'a -> ('a,'b) t -> ('a,'b) t
|
||||||
(** [remove x l] removes the first occurrence of [k] from [l].
|
(** [remove x l] removes the first occurrence of [k] from [l].
|
||||||
@since 0.17 *)
|
@since 0.17 *)
|
||||||
end
|
end
|
||||||
|
|
||||||
val assoc : eq:('a -> 'a -> bool) -> 'a -> ('a * 'b) t -> 'b
|
val assoc : eq:(('a -> 'a -> bool) [@keep_label]) -> 'a -> ('a * 'b) t -> 'b
|
||||||
(** Like [Assoc.get_exn].
|
(** Like [Assoc.get_exn].
|
||||||
@since 2.0 *)
|
@since 2.0 *)
|
||||||
|
|
||||||
val assoc_opt : eq:('a -> 'a -> bool) -> 'a -> ('a * 'b) t -> 'b option
|
val assoc_opt : eq:(('a -> 'a -> bool) [@keep_label]) -> 'a -> ('a * 'b) t -> 'b option
|
||||||
(** Like [Assoc.get].
|
(** Like [Assoc.get].
|
||||||
@since 2.0 *)
|
@since 1.5, but only
|
||||||
|
@since 2.0 with labels *)
|
||||||
|
|
||||||
val assq_opt : 'a -> ('a * 'b) t -> 'b option
|
val assq_opt : 'a -> ('a * 'b) t -> 'b option
|
||||||
(** Safe version of {!assq}.
|
(** Safe version of {!assq}.
|
||||||
@since 2.0 *)
|
@since 1.5, but only
|
||||||
|
@since 2.0 with labels *)
|
||||||
|
|
||||||
val mem_assoc : eq:('a -> 'a -> bool) -> 'a -> ('a * _) t -> bool
|
val mem_assoc : eq:(('a -> 'a -> bool) [@keep_label]) -> 'a -> ('a * _) t -> bool
|
||||||
(** Like [Assoc.mem].
|
(** Like [Assoc.mem].
|
||||||
@since 2.0 *)
|
@since 2.0 *)
|
||||||
|
|
||||||
val remove_assoc : eq:('a -> 'a -> bool) -> 'a -> ('a * 'b) t -> ('a * 'b) t
|
val remove_assoc : eq:(('a -> 'a -> bool) [@keep_label]) -> 'a -> ('a * 'b) t -> ('a * 'b) t
|
||||||
(** Like [Assoc.remove].
|
(** Like [Assoc.remove].
|
||||||
@since 2.0 *)
|
@since 2.0 *)
|
||||||
|
|
||||||
|
|
@ -567,7 +657,6 @@ module type MONAD = sig
|
||||||
|
|
||||||
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
|
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
|
||||||
(** Monadic [bind]. *)
|
(** Monadic [bind]. *)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module Traverse(M : MONAD) : sig
|
module Traverse(M : MONAD) : sig
|
||||||
|
|
@ -599,19 +688,22 @@ val to_seq : 'a t -> 'a sequence
|
||||||
(** Return a [sequence] of the elements of the list. *)
|
(** Return a [sequence] of the elements of the list. *)
|
||||||
|
|
||||||
val of_seq : 'a sequence -> 'a t
|
val of_seq : 'a sequence -> 'a t
|
||||||
(** Build a list from a given [sequence]. *)
|
(** Build a list from a given [sequence].
|
||||||
|
In the result, elements appear in the same order as they did in the source [sequence]. *)
|
||||||
|
|
||||||
val to_gen : 'a t -> 'a gen
|
val to_gen : 'a t -> 'a gen
|
||||||
(** Return a [gen] of the elements of the list. *)
|
(** Return a [gen] of the elements of the list. *)
|
||||||
|
|
||||||
val of_gen : 'a gen -> 'a t
|
val of_gen : 'a gen -> 'a t
|
||||||
(** Build a list from a given [gen]. *)
|
(** Build a list from a given [gen].
|
||||||
|
In the result, elements appear in the same order as they did in the source [gen]. *)
|
||||||
|
|
||||||
val to_klist : 'a t -> 'a klist
|
val to_klist : 'a t -> 'a klist
|
||||||
(** Return a [klist] of the elements of the list. *)
|
(** Return a [klist] of the elements of the list. *)
|
||||||
|
|
||||||
val of_klist : 'a klist -> 'a t
|
val of_klist : 'a klist -> 'a t
|
||||||
(** Build a list from a given [klist]. *)
|
(** Build a list from a given [klist].
|
||||||
|
In the result, elements appear in the same order as they did in the source [klist]. *)
|
||||||
|
|
||||||
(** {2 Infix Operators}
|
(** {2 Infix Operators}
|
||||||
It is convenient to {!open CCList.Infix} to access the infix operators
|
It is convenient to {!open CCList.Infix} to access the infix operators
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
(* AUTOGENERATED FROM CCStringLabels.mli *)
|
||||||
|
|
||||||
|
|
||||||
(* This file is free software, part of containers. See file "license" for more details. *)
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
|
|
@ -142,7 +144,7 @@ val replace : ?which:[`Left|`Right|`All] -> sub:string -> by:string -> string ->
|
||||||
@raise Invalid_argument if [sub = ""].
|
@raise Invalid_argument if [sub = ""].
|
||||||
@since 0.14 *)
|
@since 0.14 *)
|
||||||
|
|
||||||
val is_sub : sub:string -> int -> string -> int -> len:int -> bool
|
val is_sub : sub:string -> int -> string -> int -> sub_len:int -> bool
|
||||||
(** [is_sub ~sub i s j ~len] returns [true] iff the substring of
|
(** [is_sub ~sub i s j ~len] returns [true] iff the substring of
|
||||||
[sub] starting at position [i] and of length [len] is a substring
|
[sub] starting at position [i] and of length [len] is a substring
|
||||||
of [s] starting at position [j]. *)
|
of [s] starting at position [j]. *)
|
||||||
|
|
@ -333,12 +335,12 @@ module Find : sig
|
||||||
|
|
||||||
val rcompile : string -> [ `Reverse ] pattern
|
val rcompile : string -> [ `Reverse ] pattern
|
||||||
|
|
||||||
val find : ?start:int -> pattern:[`Direct] pattern -> string -> int
|
val find : ?start:int -> pattern:([`Direct] pattern) -> string -> int
|
||||||
(** Search for [pattern] in the string, left-to-right.
|
(** Search for [pattern] in the string, left-to-right.
|
||||||
@return the offset of the first match, -1 otherwise.
|
@return the offset of the first match, -1 otherwise.
|
||||||
@param start offset in string at which we start. *)
|
@param start offset in string at which we start. *)
|
||||||
|
|
||||||
val rfind : ?start:int -> pattern:[`Reverse] pattern -> string -> int
|
val rfind : ?start:int -> pattern:([`Reverse] pattern) -> string -> int
|
||||||
(** Search for [pattern] in the string, right-to-left.
|
(** Search for [pattern] in the string, right-to-left.
|
||||||
@return the offset of the start of the first match from the right, -1 otherwise.
|
@return the offset of the start of the first match from the right, -1 otherwise.
|
||||||
@param start right-offset in string at which we start. *)
|
@param start right-offset in string at which we start. *)
|
||||||
|
|
|
||||||
4
src/core/CCStringLabels.ml
Normal file
4
src/core/CCStringLabels.ml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
|
||||||
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
|
include CCString
|
||||||
472
src/core/CCStringLabels.mli
Normal file
472
src/core/CCStringLabels.mli
Normal file
|
|
@ -0,0 +1,472 @@
|
||||||
|
|
||||||
|
(* This file is free software, part of containers. See file "license" for more details. *)
|
||||||
|
|
||||||
|
(** {1 Basic String Utils} *)
|
||||||
|
|
||||||
|
type 'a gen = unit -> 'a option
|
||||||
|
type 'a sequence = ('a -> unit) -> unit
|
||||||
|
type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist]
|
||||||
|
|
||||||
|
(** {2 Common Signature} *)
|
||||||
|
|
||||||
|
module type S = sig
|
||||||
|
type t
|
||||||
|
|
||||||
|
val length : t -> int
|
||||||
|
(** Return the length (number of characters) of the given string. *)
|
||||||
|
|
||||||
|
val blit : src:t -> src_pos:int -> dst:Bytes.t -> dst_pos:int -> len:int -> unit
|
||||||
|
(** Like {!String.blit}.
|
||||||
|
Compatible with the [-safe-string] option.
|
||||||
|
@raise Invalid_argument if indices are not valid. *)
|
||||||
|
|
||||||
|
(*
|
||||||
|
val blit_immut : t -> int -> t -> int -> int -> string
|
||||||
|
(** Immutable version of {!blit}, returning a new string.
|
||||||
|
[blit a i b j len] is the same as [b], but in which
|
||||||
|
the range [j, ..., j+len] is replaced by [a.[i], ..., a.[i + len]].
|
||||||
|
@raise Invalid_argument if indices are not valid. *)
|
||||||
|
*)
|
||||||
|
|
||||||
|
val fold : f:('a -> char -> 'a) -> init:'a -> t -> 'a
|
||||||
|
(** Fold on chars by increasing index.
|
||||||
|
@since 0.7 *)
|
||||||
|
|
||||||
|
(** {2 Conversions} *)
|
||||||
|
|
||||||
|
val to_gen : t -> char gen
|
||||||
|
(** Return the [gen] of characters contained in the string. *)
|
||||||
|
|
||||||
|
val to_seq : t -> char sequence
|
||||||
|
(** Return the [sequence] of characters contained in the string. *)
|
||||||
|
|
||||||
|
val to_klist : t -> char klist
|
||||||
|
(** Return the [klist] of characters contained in the string. *)
|
||||||
|
|
||||||
|
val to_list : t -> char list
|
||||||
|
(** Return the list of characters contained in the string. *)
|
||||||
|
|
||||||
|
val pp_buf : Buffer.t -> t -> unit
|
||||||
|
(** Renamed from [pp] since 2.0. *)
|
||||||
|
|
||||||
|
val pp : Format.formatter -> t -> unit
|
||||||
|
(** Print the string within quotes.
|
||||||
|
|
||||||
|
Renamed from [print] since 2.0. *)
|
||||||
|
end
|
||||||
|
|
||||||
|
(** {2 Strings} *)
|
||||||
|
|
||||||
|
include module type of struct include StringLabels end
|
||||||
|
|
||||||
|
val equal : string -> string -> bool
|
||||||
|
(** Equality function on strings. *)
|
||||||
|
|
||||||
|
val compare : string -> string -> int
|
||||||
|
|
||||||
|
val is_empty : string -> bool
|
||||||
|
(** [is_empty s] returns [true] iff [s] is empty (i.e. its length is 0).
|
||||||
|
@since 1.5 *)
|
||||||
|
|
||||||
|
val hash : string -> int
|
||||||
|
|
||||||
|
val init : int -> (int -> char) -> string
|
||||||
|
(** Like [Array.init].
|
||||||
|
@since 0.3.3 *)
|
||||||
|
|
||||||
|
val rev : string -> string
|
||||||
|
(** [rev s] returns the reverse of [s].
|
||||||
|
@since 0.17 *)
|
||||||
|
|
||||||
|
val pad : ?side:[`Left|`Right] -> ?c:char -> int -> string -> string
|
||||||
|
(** [pad n str] ensures that [str] is at least [n] bytes long,
|
||||||
|
and pads it on the [side] with [c] if it's not the case.
|
||||||
|
@param side determines where padding occurs (default: [`Left]).
|
||||||
|
@param c the char used to pad (default: ' ').
|
||||||
|
@since 0.17 *)
|
||||||
|
|
||||||
|
val of_char : char -> string
|
||||||
|
(** [of_char 'a'] is ["a"].
|
||||||
|
@since 0.19 *)
|
||||||
|
|
||||||
|
val of_gen : char gen -> string
|
||||||
|
(** Convert a [gen] of characters to a string. *)
|
||||||
|
|
||||||
|
val of_seq : char sequence -> string
|
||||||
|
(** Convert a [sequence] of characters to a string. *)
|
||||||
|
|
||||||
|
val of_klist : char klist -> string
|
||||||
|
(** Convert a [klist] of characters to a string. *)
|
||||||
|
|
||||||
|
val of_list : char list -> string
|
||||||
|
(** Convert a list of characters to a string. *)
|
||||||
|
|
||||||
|
val of_array : char array -> string
|
||||||
|
(** Convert an array of characters to a string. *)
|
||||||
|
|
||||||
|
val to_array : string -> char array
|
||||||
|
(** Return the array of characters contained in the string. *)
|
||||||
|
|
||||||
|
val find : ?start:int -> sub:(string [@keep_label]) -> string -> int
|
||||||
|
(** Find [sub] in string, returns its first index or [-1]. *)
|
||||||
|
|
||||||
|
val find_all : ?start:int -> sub:(string [@keep_label]) -> string -> int gen
|
||||||
|
(** [find_all ~sub s] finds all occurrences of [sub] in [s], even overlapping
|
||||||
|
instances.
|
||||||
|
@param start starting position in [s].
|
||||||
|
@since 0.17 *)
|
||||||
|
|
||||||
|
val find_all_l : ?start:int -> sub:(string [@keep_label]) -> string -> int list
|
||||||
|
(** [find_all_l ~sub s] finds all occurrences of [sub] in [s] and returns
|
||||||
|
them in a list.
|
||||||
|
@param start starting position in [s].
|
||||||
|
@since 0.17 *)
|
||||||
|
|
||||||
|
val mem : ?start:int -> sub:(string [@keep_label]) -> string -> bool
|
||||||
|
(** [mem ~sub s] is [true] iff [sub] is a substring of [s].
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val rfind : sub:(string [@keep_label]) -> string -> int
|
||||||
|
(** Find [sub] in string from the right, returns its first index or [-1].
|
||||||
|
Should only be used with very small [sub].
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val replace : ?which:[`Left|`Right|`All] -> sub:(string [@keep_label]) -> by:(string [@keep_label]) -> string -> string
|
||||||
|
(** [replace ~sub ~by s] replaces some occurrences of [sub] by [by] in [s].
|
||||||
|
@param which decides whether the occurrences to replace are:
|
||||||
|
{ul
|
||||||
|
{- [`Left] first occurrence from the left (beginning).}
|
||||||
|
{- [`Right] first occurrence from the right (end).}
|
||||||
|
{- [`All] all occurrences (default).}
|
||||||
|
}
|
||||||
|
@raise Invalid_argument if [sub = ""].
|
||||||
|
@since 0.14 *)
|
||||||
|
|
||||||
|
val is_sub : sub:(string [@keep_label]) -> sub_pos:int -> string -> pos:int -> sub_len:(int [@keep_label]) -> bool
|
||||||
|
(** [is_sub ~sub i s j ~len] returns [true] iff the substring of
|
||||||
|
[sub] starting at position [i] and of length [len] is a substring
|
||||||
|
of [s] starting at position [j]. *)
|
||||||
|
|
||||||
|
val repeat : string -> int -> string
|
||||||
|
(** The same string, repeated n times. *)
|
||||||
|
|
||||||
|
val prefix : pre:(string [@keep_label]) -> string -> bool
|
||||||
|
(** [prefix ~pre s] returns [true] iff [pre] is a prefix of [s]. *)
|
||||||
|
|
||||||
|
val suffix : suf:(string [@keep_label]) -> string -> bool
|
||||||
|
(** [suffix ~suf s] returns [true] iff [suf] is a suffix of [s].
|
||||||
|
@since 0.7 *)
|
||||||
|
|
||||||
|
val chop_prefix : pre:(string [@keep_label]) -> string -> string option
|
||||||
|
(** [chop_prefix ~pre s] removes [pre] from [s] if [pre] really is a prefix
|
||||||
|
of [s], returns [None] otherwise.
|
||||||
|
@since 0.17 *)
|
||||||
|
|
||||||
|
val chop_suffix : suf:(string [@keep_label]) -> string -> string option
|
||||||
|
(** [chop_suffix ~suf s] removes [suf] from [s] if [suf] really is a suffix
|
||||||
|
of [s], returns [None] otherwise.
|
||||||
|
@since 0.17 *)
|
||||||
|
|
||||||
|
val take : int -> string -> string
|
||||||
|
(** [take n s] keeps only the [n] first chars of [s].
|
||||||
|
@since 0.17 *)
|
||||||
|
|
||||||
|
val drop : int -> string -> string
|
||||||
|
(** [drop n s] removes the [n] first chars of [s].
|
||||||
|
@since 0.17 *)
|
||||||
|
|
||||||
|
val take_drop : int -> string -> string * string
|
||||||
|
(** [take_drop n s = take n s, drop n s].
|
||||||
|
@since 0.17 *)
|
||||||
|
|
||||||
|
val lines : string -> string list
|
||||||
|
(** [lines s] returns a list of the lines of [s] (splits along '\n').
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
val lines_gen : string -> string gen
|
||||||
|
(** [lines_gen s] returns a generator of the lines of [s] (splits along '\n').
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
val concat_gen : sep:(string [@keep_label]) -> string gen -> string
|
||||||
|
(** [concat_gen ~sep g] concatenates all strings of [g], separated with [sep].
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
val unlines : string list -> string
|
||||||
|
(** [unlines l] concatenates all strings of [l], separated with '\n'.
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
val unlines_gen : string gen -> string
|
||||||
|
(** [unlines_gen g] concatenates all strings of [g], separated with '\n'.
|
||||||
|
@since 0.10 *)
|
||||||
|
|
||||||
|
val set : string -> int -> char -> string
|
||||||
|
(** [set s i c] creates a new string which is a copy of [s], except
|
||||||
|
for index [i], which becomes [c].
|
||||||
|
@raise Invalid_argument if [i] is an invalid index.
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val iter : f:(char -> unit) -> string -> unit
|
||||||
|
(** Alias to {!String.iter}.
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val iteri : f:(int -> char -> unit) -> string -> unit
|
||||||
|
(** Iter on chars with their index.
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val map : f:(char -> char) -> string -> string
|
||||||
|
(** Map chars.
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val mapi : f:(int -> char -> char) -> string -> string
|
||||||
|
(** Map chars with their index.
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val filter_map : f:(char -> char option) -> string -> string
|
||||||
|
(** [filter_map f s] calls [(f a0) (f a1) ... (f an)] where [a0 ... an] are the characters of s.
|
||||||
|
It returns the string of characters [ci] such as [f ai = Some ci] (when [f] returns [None],
|
||||||
|
the corresponding element of [s] is discarded).
|
||||||
|
@since 0.17 *)
|
||||||
|
|
||||||
|
val filter : f:(char -> bool) -> string -> string
|
||||||
|
(** [filter f s] discards characters not satisfying [f].
|
||||||
|
@since 0.17 *)
|
||||||
|
|
||||||
|
val flat_map : ?sep:string -> f:(char -> string) -> string -> string
|
||||||
|
(** Map each chars to a string, then concatenates them all.
|
||||||
|
@param sep optional separator between each generated string.
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val for_all : f:(char -> bool) -> string -> bool
|
||||||
|
(** True for all chars?
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val exists : f:(char -> bool) -> string -> bool
|
||||||
|
(** True for some char?
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
include S with type t := string
|
||||||
|
|
||||||
|
val drop_while : f:(char -> bool) -> t -> t
|
||||||
|
(** [drop_while f s] discards any characters starting from the left,
|
||||||
|
up to the first character [c] not satisfying [f c].
|
||||||
|
@since 2.2 *)
|
||||||
|
|
||||||
|
val rdrop_while : f:(char -> bool) -> t -> t
|
||||||
|
(** [rdrop_while f s] discards any characters starting from the right,
|
||||||
|
up to the first character [c] not satisfying [f c].
|
||||||
|
@since 2.2 *)
|
||||||
|
|
||||||
|
val ltrim : t -> t
|
||||||
|
(** Trim space on the left (see {!String.trim} for more details).
|
||||||
|
@since 1.2 *)
|
||||||
|
|
||||||
|
val rtrim : t -> t
|
||||||
|
(** Trim space on the right (see {!String.trim} for more details).
|
||||||
|
@since 1.2 *)
|
||||||
|
|
||||||
|
(** {2 Operations on 2 strings} *)
|
||||||
|
|
||||||
|
val map2 : f:(char -> char -> char) -> string -> string -> string
|
||||||
|
(** Map pairs of chars.
|
||||||
|
@raise Invalid_argument if the strings have not the same length.
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val iter2: f:(char -> char -> unit) -> string -> string -> unit
|
||||||
|
(** Iterate on pairs of chars.
|
||||||
|
@raise Invalid_argument if the strings have not the same length.
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val iteri2: f:(int -> char -> char -> unit) -> string -> string -> unit
|
||||||
|
(** Iterate on pairs of chars with their index.
|
||||||
|
@raise Invalid_argument if the strings have not the same length.
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val fold2: f:('a -> char -> char -> 'a) -> init:'a -> string -> string -> 'a
|
||||||
|
(** Fold on pairs of chars.
|
||||||
|
@raise Invalid_argument if the strings have not the same length.
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val for_all2 : f:(char -> char -> bool) -> string -> string -> bool
|
||||||
|
(** All pairs of chars respect the predicate?
|
||||||
|
@raise Invalid_argument if the strings have not the same length.
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val exists2 : f:(char -> char -> bool) -> string -> string -> bool
|
||||||
|
(** Exists a pair of chars?
|
||||||
|
@raise Invalid_argument if the strings have not the same length.
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
(** {2 Ascii functions}
|
||||||
|
|
||||||
|
Those functions are deprecated in {!String} since 4.03, so we provide
|
||||||
|
a stable alias for them even in older versions. *)
|
||||||
|
|
||||||
|
val capitalize_ascii : string -> string
|
||||||
|
(** See {!String}.
|
||||||
|
@since 0.18 *)
|
||||||
|
|
||||||
|
val uncapitalize_ascii : string -> string
|
||||||
|
(** See {!String}.
|
||||||
|
@since 0.18 *)
|
||||||
|
|
||||||
|
val uppercase_ascii : string -> string
|
||||||
|
(** See {!String}.
|
||||||
|
@since 0.18 *)
|
||||||
|
|
||||||
|
val lowercase_ascii : string -> string
|
||||||
|
(** See {!String}.
|
||||||
|
@since 0.18 *)
|
||||||
|
|
||||||
|
val equal_caseless : string -> string -> bool
|
||||||
|
(** Comparison without respect to {b ascii} lowercase.
|
||||||
|
@since 1.2 *)
|
||||||
|
|
||||||
|
(** {2 Finding}
|
||||||
|
|
||||||
|
A relatively efficient algorithm for finding sub-strings.
|
||||||
|
@since 1.0 *)
|
||||||
|
|
||||||
|
module Find : sig
|
||||||
|
type _ pattern
|
||||||
|
|
||||||
|
val compile : string -> [ `Direct ] pattern
|
||||||
|
|
||||||
|
val rcompile : string -> [ `Reverse ] pattern
|
||||||
|
|
||||||
|
val find : ?start:int -> pattern:(([`Direct] pattern) [@keep_label]) -> string -> int
|
||||||
|
(** Search for [pattern] in the string, left-to-right.
|
||||||
|
@return the offset of the first match, -1 otherwise.
|
||||||
|
@param start offset in string at which we start. *)
|
||||||
|
|
||||||
|
val rfind : ?start:int -> pattern:(([`Reverse] pattern) [@keep_label]) -> string -> int
|
||||||
|
(** Search for [pattern] in the string, right-to-left.
|
||||||
|
@return the offset of the start of the first match from the right, -1 otherwise.
|
||||||
|
@param start right-offset in string at which we start. *)
|
||||||
|
end
|
||||||
|
|
||||||
|
(** {2 Splitting} *)
|
||||||
|
|
||||||
|
module Split : sig
|
||||||
|
(** Specification of what to do with empty blocks, as in [split ~by:"-" "-a-b-"].
|
||||||
|
|
||||||
|
- [{first=false; last=false}] will return [""; "a"; "b"; ""]
|
||||||
|
- [{first=true; last=false}] will return ["a"; "b" ""]
|
||||||
|
- [{first=false; last=true}] will return [""; "a"; "b"]
|
||||||
|
- [{first=true; last=true}] will return ["a"; "b"]
|
||||||
|
|
||||||
|
The default value of all remaining functions is [Drop_none].
|
||||||
|
@since 1.5
|
||||||
|
*)
|
||||||
|
type drop_if_empty = {
|
||||||
|
first: bool;
|
||||||
|
last: bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
val no_drop : drop_if_empty
|
||||||
|
(** Do not drop any group, even empty and on borders.
|
||||||
|
@since 1.5 *)
|
||||||
|
|
||||||
|
val list_ : ?drop:drop_if_empty -> by:(string [@keep_label]) -> string -> (string*int*int) list
|
||||||
|
(** Split the given string along the given separator [by]. Should only
|
||||||
|
be used with very small separators, otherwise
|
||||||
|
use {!Containers_string.KMP}.
|
||||||
|
@return a list of slices [(s,index,length)] that are
|
||||||
|
separated by [by]. {!String.sub} can then be used to actually extract
|
||||||
|
a string from the slice.
|
||||||
|
@raise Failure if [by = ""]. *)
|
||||||
|
|
||||||
|
val gen : ?drop:drop_if_empty -> by:(string [@keep_label]) -> string -> (string*int*int) gen
|
||||||
|
|
||||||
|
val seq : ?drop:drop_if_empty -> by:(string [@keep_label]) -> string -> (string*int*int) sequence
|
||||||
|
|
||||||
|
val klist : ?drop:drop_if_empty -> by:(string [@keep_label]) -> string -> (string*int*int) klist
|
||||||
|
|
||||||
|
(** {4 Copying functions}
|
||||||
|
|
||||||
|
Those split functions actually copy the substrings, which can be
|
||||||
|
more convenient but less efficient in general. *)
|
||||||
|
|
||||||
|
val list_cpy : ?drop:drop_if_empty -> by:(string [@keep_label]) -> string -> string list
|
||||||
|
|
||||||
|
val gen_cpy : ?drop:drop_if_empty -> by:(string [@keep_label]) -> string -> string gen
|
||||||
|
|
||||||
|
val seq_cpy : ?drop:drop_if_empty -> by:(string [@keep_label]) -> string -> string sequence
|
||||||
|
|
||||||
|
val klist_cpy : ?drop:drop_if_empty -> by:(string [@keep_label]) -> string -> string klist
|
||||||
|
|
||||||
|
val left : by:(string [@keep_label]) -> string -> (string * string) option
|
||||||
|
(** Split on the first occurrence of [by] from the leftmost part of
|
||||||
|
the string.
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val left_exn : by:(string [@keep_label]) -> string -> string * string
|
||||||
|
(** Split on the first occurrence of [by] from the leftmost part of the string.
|
||||||
|
@raise Not_found if [by] is not part of the string.
|
||||||
|
@since 0.16 *)
|
||||||
|
|
||||||
|
val right : by:(string [@keep_label]) -> string -> (string * string) option
|
||||||
|
(** Split on the first occurrence of [by] from the rightmost part of
|
||||||
|
the string.
|
||||||
|
@since 0.12 *)
|
||||||
|
|
||||||
|
val right_exn : by:(string [@keep_label]) -> string -> string * string
|
||||||
|
(** Split on the first occurrence of [by] from the rightmost part of the string.
|
||||||
|
@raise Not_found if [by] is not part of the string.
|
||||||
|
@since 0.16 *)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
val split_on_char : by:char -> string -> string list
|
||||||
|
(** Split the string along the given char.
|
||||||
|
@since 1.2 *)
|
||||||
|
|
||||||
|
val split : by:(string [@keep_label]) -> string -> string list
|
||||||
|
(** Alias to {!Split.list_cpy}.
|
||||||
|
@since 1.2 *)
|
||||||
|
|
||||||
|
(** {2 Utils} *)
|
||||||
|
|
||||||
|
val compare_versions : string -> string -> int
|
||||||
|
(** [compare_versions a b] compares {i version strings} [ a] and [b],
|
||||||
|
considering that numbers are above text.
|
||||||
|
@since 0.13 *)
|
||||||
|
|
||||||
|
val compare_natural : string -> string -> int
|
||||||
|
(** Natural Sort Order, comparing chunks of digits as natural numbers.
|
||||||
|
https://en.wikipedia.org/wiki/Natural_sort_order
|
||||||
|
@since 1.3 *)
|
||||||
|
|
||||||
|
val edit_distance : string -> string -> int
|
||||||
|
(** Edition distance between two strings. This satisfies the classical
|
||||||
|
distance axioms: it is always positive, symmetric, and satisfies
|
||||||
|
the formula [distance a b + distance b c >= distance a c]. *)
|
||||||
|
|
||||||
|
(** {2 Slices}
|
||||||
|
|
||||||
|
A contiguous part of a string *)
|
||||||
|
|
||||||
|
module Sub : sig
|
||||||
|
type t = string * int * int
|
||||||
|
(** A string, an offset, and the length of the slice. *)
|
||||||
|
|
||||||
|
val make : string -> pos:int -> len:(int [@keep_label]) -> t
|
||||||
|
|
||||||
|
val full : string -> t
|
||||||
|
(** Full string. *)
|
||||||
|
|
||||||
|
val copy : t -> string
|
||||||
|
(** Make a copy of the substring. *)
|
||||||
|
|
||||||
|
val underlying : t -> string
|
||||||
|
|
||||||
|
val sub : t -> int -> int -> t
|
||||||
|
(** Sub-slice. *)
|
||||||
|
|
||||||
|
val get : t -> int -> char
|
||||||
|
(** [get s i] gets the [i]-th element, or fails.
|
||||||
|
@raise Invalid_argument if the index is not within [0 ... length - 1].
|
||||||
|
@since 1.2 *)
|
||||||
|
|
||||||
|
include S with type t := t
|
||||||
|
|
||||||
|
end
|
||||||
|
|
@ -6,9 +6,11 @@
|
||||||
module Array = CCArray
|
module Array = CCArray
|
||||||
module ArrayLabels = CCArrayLabels
|
module ArrayLabels = CCArrayLabels
|
||||||
module Array_slice = CCArray_slice
|
module Array_slice = CCArray_slice
|
||||||
|
module Array_sliceLabels = CCArray_sliceLabels
|
||||||
module Bool = CCBool
|
module Bool = CCBool
|
||||||
module Char = Char
|
module Char = Char
|
||||||
module Equal = CCEqual
|
module Equal = CCEqual
|
||||||
|
module EqualLabels = CCEqualLabels
|
||||||
module Float = CCFloat
|
module Float = CCFloat
|
||||||
module Format = CCFormat
|
module Format = CCFormat
|
||||||
module Fun = CCFun
|
module Fun = CCFun
|
||||||
|
|
@ -43,6 +45,7 @@ module Ref = CCRef
|
||||||
module Result = CCResult
|
module Result = CCResult
|
||||||
module Set = CCSet
|
module Set = CCSet
|
||||||
module String = CCString
|
module String = CCString
|
||||||
|
module StringLabels = CCStringLabels
|
||||||
module Vector = CCVector
|
module Vector = CCVector
|
||||||
module Monomorphic = CCMonomorphic
|
module Monomorphic = CCMonomorphic
|
||||||
module Utf8_string = CCUtf8_string
|
module Utf8_string = CCUtf8_string
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,32 @@
|
||||||
|
(rule
|
||||||
|
(targets CCArray.mli)
|
||||||
|
(deps CCArrayLabels.mli)
|
||||||
|
(mode promote)
|
||||||
|
(action (run ../unlabel.exe %{deps} %{targets})))
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(targets CCArray_slice.mli)
|
||||||
|
(deps CCArray_sliceLabels.mli)
|
||||||
|
(mode promote)
|
||||||
|
(action (run ../unlabel.exe %{deps} %{targets})))
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(targets CCEqual.mli)
|
||||||
|
(deps CCEqualLabels.mli)
|
||||||
|
(mode promote)
|
||||||
|
(action (run ../unlabel.exe %{deps} %{targets})))
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(targets CCList.mli)
|
||||||
|
(deps CCListLabels.mli)
|
||||||
|
(mode promote)
|
||||||
|
(action (run ../unlabel.exe %{deps} %{targets})))
|
||||||
|
|
||||||
|
(rule
|
||||||
|
(targets CCString.mli)
|
||||||
|
(deps CCStringLabels.mli)
|
||||||
|
(mode promote)
|
||||||
|
(action (run ../unlabel.exe %{deps} %{targets})))
|
||||||
|
|
||||||
(library
|
(library
|
||||||
(name containers)
|
(name containers)
|
||||||
|
|
|
||||||
8
src/dune
8
src/dune
|
|
@ -1,12 +1,16 @@
|
||||||
|
|
||||||
(executable
|
(executable
|
||||||
(name mkflags)
|
(name mkflags)
|
||||||
|
(modules mkflags)
|
||||||
(libraries dune.configurator))
|
(libraries dune.configurator))
|
||||||
|
|
||||||
|
(executable
|
||||||
|
(name unlabel)
|
||||||
|
(modules unlabel)
|
||||||
|
(libraries str compiler-libs.common))
|
||||||
|
|
||||||
(rule
|
(rule
|
||||||
(targets flambda.flags)
|
(targets flambda.flags)
|
||||||
(mode fallback)
|
(mode fallback)
|
||||||
(action
|
(action
|
||||||
(run ./mkflags.exe))
|
(run ./mkflags.exe))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
246
src/unlabel.ml
Normal file
246
src/unlabel.ml
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
(* search for first occurence of pat in s *)
|
||||||
|
let rec search pat s pos =
|
||||||
|
let rec compare i =
|
||||||
|
if i >= String.length pat
|
||||||
|
then true
|
||||||
|
else if pat.[i] = s.[pos+i]
|
||||||
|
then compare (i+1)
|
||||||
|
else false
|
||||||
|
in
|
||||||
|
if pos > String.length s - String.length pat
|
||||||
|
then raise Not_found
|
||||||
|
else if compare 0
|
||||||
|
then pos
|
||||||
|
else search pat s (pos+1)
|
||||||
|
;;
|
||||||
|
|
||||||
|
(* search all non-overlapping occurences of pat in s *)
|
||||||
|
let search_all pat s =
|
||||||
|
let rec search_rest acc pos =
|
||||||
|
let next =
|
||||||
|
try Some (search pat s pos) with
|
||||||
|
Not_found -> None
|
||||||
|
in
|
||||||
|
match next with
|
||||||
|
| None -> acc
|
||||||
|
| Some pos -> search_rest (pos::acc) (pos + String.length pat)
|
||||||
|
in
|
||||||
|
List.rev (search_rest [] 0)
|
||||||
|
;;
|
||||||
|
|
||||||
|
(* replase first occurence of pat with subst in s *)
|
||||||
|
let replace_first pat subst s =
|
||||||
|
let pos = search pat s 0 in
|
||||||
|
let patl = String.length pat
|
||||||
|
and substl = String.length subst in
|
||||||
|
let buf = Bytes.create (String.length s - patl + substl) in
|
||||||
|
Bytes.blit_string s 0 buf 0 pos;
|
||||||
|
Bytes.blit_string subst 0 buf pos substl;
|
||||||
|
Bytes.blit_string
|
||||||
|
s (pos + patl)
|
||||||
|
buf (pos + substl)
|
||||||
|
(String.length s - pos - patl);
|
||||||
|
Bytes.unsafe_to_string buf
|
||||||
|
;;
|
||||||
|
|
||||||
|
(* replase first occurence of pat with subst in s *)
|
||||||
|
let replace_all pat subst s =
|
||||||
|
let pos = search_all pat s in
|
||||||
|
let patl = String.length pat
|
||||||
|
and substl = String.length subst in
|
||||||
|
let len = String.length s + List.length pos * (substl - patl) in
|
||||||
|
let buf = Bytes.create len in
|
||||||
|
let rec loop src_pos dst_pos = function
|
||||||
|
| [] ->
|
||||||
|
Bytes.blit_string s src_pos buf dst_pos (String.length s - src_pos)
|
||||||
|
| pat_pos :: tail ->
|
||||||
|
let headl = pat_pos - src_pos in
|
||||||
|
Bytes.blit_string s src_pos buf dst_pos headl;
|
||||||
|
Bytes.blit_string subst 0 buf (dst_pos + headl) substl;
|
||||||
|
loop
|
||||||
|
(src_pos + headl + patl)
|
||||||
|
(dst_pos + headl + substl)
|
||||||
|
tail
|
||||||
|
in loop 0 0 pos;
|
||||||
|
Bytes.unsafe_to_string buf
|
||||||
|
;;
|
||||||
|
|
||||||
|
let match_closeparen s i =
|
||||||
|
assert (s.[i] = ')');
|
||||||
|
let rec loop i count =
|
||||||
|
match s.[i] with
|
||||||
|
| '(' when count = 0 -> i
|
||||||
|
| '(' -> loop (i-1) (count-1)
|
||||||
|
| ')' -> loop (i-1) (count+1)
|
||||||
|
| _ -> loop (i-1) count
|
||||||
|
in loop (i-1) 0
|
||||||
|
;;
|
||||||
|
|
||||||
|
let slurp_file file =
|
||||||
|
let ch = open_in file in
|
||||||
|
let buf = Buffer.create (min 1024 (in_channel_length ch)) in
|
||||||
|
try
|
||||||
|
while true do Buffer.add_channel buf ch 4096 done;
|
||||||
|
assert false
|
||||||
|
with
|
||||||
|
| End_of_file ->
|
||||||
|
close_in ch;
|
||||||
|
Bytes.unsafe_to_string (Buffer.to_bytes buf)
|
||||||
|
;;
|
||||||
|
|
||||||
|
let () =
|
||||||
|
assert (Array.length Sys.argv = 3);
|
||||||
|
let labelled_filename = Sys.argv.(1) in (* CCArrayLabels.mli *)
|
||||||
|
let unlabelled_filename = Sys.argv.(2) in (* CCArray.ml *)
|
||||||
|
let labelled_name = (* ArrayLabels *)
|
||||||
|
let basename =
|
||||||
|
Compenv.module_of_filename Format.err_formatter
|
||||||
|
labelled_filename
|
||||||
|
labelled_filename
|
||||||
|
in
|
||||||
|
assert (basename.[0] = 'C' && basename.[1] = 'C');
|
||||||
|
String.sub basename 2 (String.length basename - 2)
|
||||||
|
in
|
||||||
|
let unlabelled_name = (* Array *)
|
||||||
|
replace_first "Labels" "" labelled_name
|
||||||
|
in
|
||||||
|
let labelled_text = slurp_file labelled_filename in
|
||||||
|
let lexbuf = Lexing.from_string labelled_text in
|
||||||
|
Location.init lexbuf labelled_filename;
|
||||||
|
let labelled_ast = Parse.interface lexbuf in
|
||||||
|
(* stack of replacements to perform on the labelled_text.
|
||||||
|
* perform them in one run later so that the character counts
|
||||||
|
* won't be affected by earlier replacements. *)
|
||||||
|
let replacements = ref [] in
|
||||||
|
(* function removing '~' from docstring attributes where appropriate. *)
|
||||||
|
let strip_attributes labels attributes =
|
||||||
|
List.iter
|
||||||
|
begin function
|
||||||
|
| ({ Asttypes.txt = "ocaml.doc"; _ },
|
||||||
|
Parsetree.PStr [{pstr_loc =
|
||||||
|
{ loc_start = {pos_cnum = start; _}
|
||||||
|
; loc_end = {pos_cnum = stop; _}
|
||||||
|
; _}
|
||||||
|
; _
|
||||||
|
}]) ->
|
||||||
|
let docstring =
|
||||||
|
List.fold_left
|
||||||
|
(fun docstring label ->
|
||||||
|
replace_all ("~" ^ label) label docstring)
|
||||||
|
(String.sub labelled_text start (stop-start))
|
||||||
|
labels
|
||||||
|
in
|
||||||
|
replacements := (start, stop-start, docstring) :: !replacements
|
||||||
|
| _ -> ()
|
||||||
|
end
|
||||||
|
attributes
|
||||||
|
in
|
||||||
|
let iterator =
|
||||||
|
let open Ast_iterator in
|
||||||
|
let open Parsetree in
|
||||||
|
{ Ast_iterator.default_iterator with
|
||||||
|
value_description = begin fun iterator
|
||||||
|
{ pval_name = { txt = _name; _ }
|
||||||
|
; pval_type
|
||||||
|
; pval_prim = _
|
||||||
|
; pval_attributes
|
||||||
|
; pval_loc
|
||||||
|
} ->
|
||||||
|
let rec loop = function
|
||||||
|
(* match function type with label *)
|
||||||
|
| { ptyp_desc = Ptyp_arrow (Labelled label, left, right)
|
||||||
|
; ptyp_loc = {loc_start = {Lexing.pos_cnum = start; _}; _}
|
||||||
|
; ptyp_attributes
|
||||||
|
; _}
|
||||||
|
when
|
||||||
|
(* check that the argument type is not marked with [@keep_label] *)
|
||||||
|
List.for_all
|
||||||
|
(fun ({Asttypes.txt; _}, _) -> txt <> "keep_label")
|
||||||
|
left.ptyp_attributes
|
||||||
|
->
|
||||||
|
assert (label = String.sub labelled_text start (String.length label));
|
||||||
|
let colon = String.index_from labelled_text start ':' in
|
||||||
|
(* remove label *)
|
||||||
|
replacements := (start, colon+1-start, "") :: !replacements;
|
||||||
|
(* remove labels from associated docstrings *)
|
||||||
|
strip_attributes [label] ptyp_attributes;
|
||||||
|
label :: loop right
|
||||||
|
| { ptyp_desc = Ptyp_arrow (_, _left, right); _} ->
|
||||||
|
loop right
|
||||||
|
| _ -> []
|
||||||
|
in
|
||||||
|
let labels = loop pval_type in
|
||||||
|
strip_attributes labels pval_attributes;
|
||||||
|
iterator.attributes iterator pval_attributes;
|
||||||
|
iterator.location iterator pval_loc;
|
||||||
|
iterator.typ iterator pval_type;
|
||||||
|
end
|
||||||
|
; attribute = begin fun iterator
|
||||||
|
({Asttypes.txt
|
||||||
|
; loc =
|
||||||
|
{ loc_start = {pos_cnum = start; _}
|
||||||
|
; loc_end = {pos_cnum = stop; _}
|
||||||
|
; _} as loc
|
||||||
|
}, _) ->
|
||||||
|
if txt = "keep_label"
|
||||||
|
then begin
|
||||||
|
(* start and stop positions mark the location of only the label name.
|
||||||
|
* Therefore search for enclosing brackets. *)
|
||||||
|
let start = String.rindex_from labelled_text start '['
|
||||||
|
and stop = String. index_from labelled_text stop ']' in
|
||||||
|
(* remove leading ' ', too *)
|
||||||
|
let start =
|
||||||
|
if labelled_text.[start-1] = ' ' then start-1 else start
|
||||||
|
in
|
||||||
|
(* if a closing paren follows, remove this and the matching paren,
|
||||||
|
* this will hopefully be the right thing to do. *)
|
||||||
|
let stop =
|
||||||
|
if labelled_text.[stop+1] = ')'
|
||||||
|
then
|
||||||
|
let openp = match_closeparen labelled_text (stop+1) in
|
||||||
|
replacements := (openp, 1, "") :: !replacements;
|
||||||
|
stop+1
|
||||||
|
else
|
||||||
|
stop
|
||||||
|
in
|
||||||
|
replacements := (start, stop-start+1, "") :: !replacements;
|
||||||
|
end;
|
||||||
|
iterator.location iterator loc
|
||||||
|
end
|
||||||
|
}
|
||||||
|
in
|
||||||
|
iterator.signature iterator labelled_ast;
|
||||||
|
|
||||||
|
(* sort replacements in ascending order. *)
|
||||||
|
let replacements =
|
||||||
|
List.sort (fun (p1,_,_) (p2,_,_) -> compare p1 p2) !replacements
|
||||||
|
in
|
||||||
|
|
||||||
|
(* perform the replacements by blitting to a buffer. *)
|
||||||
|
let unlabelled_text = Buffer.create (String.length labelled_text) in
|
||||||
|
List.fold_left begin fun start (pos,len,subst) ->
|
||||||
|
assert (pos >= start);
|
||||||
|
Buffer.add_substring unlabelled_text labelled_text start (pos - start);
|
||||||
|
Buffer.add_string unlabelled_text subst;
|
||||||
|
pos+len
|
||||||
|
end
|
||||||
|
0
|
||||||
|
replacements
|
||||||
|
|> fun start ->
|
||||||
|
Buffer.add_substring unlabelled_text
|
||||||
|
labelled_text start (String.length labelled_text - start);
|
||||||
|
|
||||||
|
let unlabelled_text =
|
||||||
|
Buffer.contents unlabelled_text
|
||||||
|
(* CCArrayLabels -> CCArray *)
|
||||||
|
|> replace_all labelled_name unlabelled_name
|
||||||
|
in
|
||||||
|
|
||||||
|
let out = open_out unlabelled_filename in
|
||||||
|
output_string out (
|
||||||
|
"(* AUTOGENERATED FROM " ^
|
||||||
|
labelled_filename
|
||||||
|
^ " *)\n\n");
|
||||||
|
output_string out unlabelled_text;
|
||||||
|
close_out out;
|
||||||
|
;;
|
||||||
Loading…
Add table
Reference in a new issue