mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-06 11:15:31 -05:00
Merge branch 'master' into add_negate
This commit is contained in:
commit
cbff4e5a39
7 changed files with 165 additions and 18 deletions
|
|
@ -19,4 +19,5 @@
|
|||
- Malcolm Matalka (`orbitz`)
|
||||
- David Sheets (@dsheets)
|
||||
- Glenn Slotte (glennsl)
|
||||
- @LemonBoy
|
||||
- Leonid Rozenberg (@rleonid)
|
||||
|
|
@ -39,6 +39,46 @@ let nativeint fmt n = Format.fprintf fmt "%nd" n
|
|||
let string_quoted fmt s = Format.fprintf fmt "\"%s\"" s
|
||||
let flush = Format.pp_print_flush
|
||||
|
||||
let newline = Format.pp_force_newline
|
||||
|
||||
let substring out (s,i,len): unit =
|
||||
string out (String.sub s i len)
|
||||
|
||||
let text out (s:string): unit =
|
||||
let len = String.length s in
|
||||
let i = ref 0 in
|
||||
let search_ c =
|
||||
try Some (String.index_from s !i c) with Not_found -> None
|
||||
in
|
||||
while !i < len do
|
||||
let j_newline = search_ '\n' in
|
||||
let j_space = search_ ' ' in
|
||||
let on_newline j =
|
||||
substring out (s, !i, j - !i);
|
||||
newline out ();
|
||||
i := j + 1
|
||||
and on_space j =
|
||||
substring out (s, !i, j - !i);
|
||||
Format.pp_print_space out ();
|
||||
i := j + 1
|
||||
in
|
||||
begin match j_newline, j_space with
|
||||
| None, None ->
|
||||
(* done *)
|
||||
substring out (s, !i, len - !i);
|
||||
i := len
|
||||
| Some j, None -> on_newline j
|
||||
| None, Some j -> on_space j
|
||||
| Some j1, Some j2 ->
|
||||
if j1<j2 then on_newline j1 else on_space j2
|
||||
end
|
||||
done
|
||||
|
||||
(*$= & ~printer:(fun s->CCFormat.sprintf "%S" s)
|
||||
"a\nb\nc" (sprintf_no_color "@[<v>%a@]%!" text "a b c")
|
||||
"a b\nc" (sprintf_no_color "@[<h>%a@]%!" text "a b\nc")
|
||||
*)
|
||||
|
||||
let list ?(sep=return ",@ ") pp fmt l =
|
||||
let rec pp_list l = match l with
|
||||
| x::((_::_) as l) ->
|
||||
|
|
|
|||
|
|
@ -23,6 +23,23 @@ val bool : bool printer
|
|||
val float3 : float printer (* 3 digits after . *)
|
||||
val float : float printer
|
||||
|
||||
val newline : unit printer
|
||||
(** Force newline (see {!Format.pp_force_newline})
|
||||
@since NEXT_RELEASE *)
|
||||
|
||||
val substring : (string * int * int) printer
|
||||
(** Print the substring [(s,i,len)], where [i] is the offset
|
||||
in [s] and [len] the number of bytes in the substring.
|
||||
@raise Invalid_argument if the triple [(s,i,len)] does not
|
||||
describe a proper substring.
|
||||
@since NEXT_RELEASE *)
|
||||
|
||||
val text : string printer
|
||||
(** Print string, but replacing spaces with breaks and newlines
|
||||
with {!newline}.
|
||||
See [pp_print_text] on recent versions of OCaml.
|
||||
@since NEXT_RELEASE *)
|
||||
|
||||
val char : char printer (** @since 0.14 *)
|
||||
val int32 : int32 printer (** @since 0.14 *)
|
||||
val int64 : int64 printer (** @since 0.14 *)
|
||||
|
|
|
|||
|
|
@ -339,6 +339,52 @@ let partition_map f l =
|
|||
assert_equal [1;3] l2
|
||||
*)
|
||||
|
||||
let combine l1 l2 =
|
||||
let rec direct i l1 l2 = match l1, l2 with
|
||||
| ([], []) -> []
|
||||
| _ when i=0 -> safe l1 l2 []
|
||||
| (x1::l1', x2::l2') -> (x1, x2) :: direct (i-1) l1' l2'
|
||||
| (_, _) -> invalid_arg "CCList.combine"
|
||||
and safe l1 l2 acc = match l1, l2 with
|
||||
| ([], []) -> List.rev acc
|
||||
| (x1::l1', x2::l2') -> safe l1' l2' @@ (x1, x2) :: acc
|
||||
| (_, _) -> invalid_arg "CCList.combine"
|
||||
in
|
||||
direct direct_depth_default_ l1 l2
|
||||
|
||||
(*$T
|
||||
try ignore (combine [1] []); false with Invalid_argument _ -> true
|
||||
try ignore (combine (1--1001) (1--1002)); false with Invalid_argument _ -> true
|
||||
combine [1;2;3] [3;2;1] = List.combine [1;2;3] [3;2;1]
|
||||
combine (1 -- 100_000) (1 -- 100_000) = List.combine (1 -- 100_000) (1 -- 100_000)
|
||||
*)
|
||||
|
||||
(*$Q
|
||||
Q.(let p = small_list int in pair p p)(fun (l1,l2) -> \
|
||||
if List.length l1=List.length l2 \
|
||||
then CCList.combine l1 l2 = List.combine l1 l2 \
|
||||
else Q.assume_fail() )
|
||||
*)
|
||||
|
||||
let combine_gen l1 l2 =
|
||||
let l1 = ref l1 in
|
||||
let l2 = ref l2 in
|
||||
fun () -> match !l1, !l2 with
|
||||
| [], _
|
||||
| _, [] -> None
|
||||
| x1 :: tail1, x2 :: tail2 ->
|
||||
l1 := tail1;
|
||||
l2 := tail2;
|
||||
Some (x1,x2)
|
||||
|
||||
(*$Q
|
||||
Q.(let p = small_list int in pair p p)(fun (l1,l2) -> \
|
||||
let n = min (List.length l1) (List.length l2) in \
|
||||
let res1 = combine (take n l1) (take n l2) in \
|
||||
let res2 = combine_gen l1 l2 |> of_gen in \
|
||||
res1 = res2)
|
||||
*)
|
||||
|
||||
let return x = [x]
|
||||
|
||||
let (>>=) l f = flat_map f l
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
|
||||
(** {1 complements to list} *)
|
||||
|
||||
type 'a sequence = ('a -> unit) -> unit
|
||||
type 'a gen = unit -> 'a option
|
||||
type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist]
|
||||
type 'a printer = Format.formatter -> 'a -> unit
|
||||
type 'a random_gen = Random.State.t -> 'a
|
||||
|
||||
type 'a t = 'a list
|
||||
|
||||
val empty : 'a t
|
||||
|
|
@ -72,6 +78,18 @@ val init : int -> (int -> 'a) -> 'a t
|
|||
(** Similar to {!Array.init}
|
||||
@since 0.6 *)
|
||||
|
||||
val combine : 'a list -> 'b list -> ('a * 'b) list
|
||||
(** Similar to {!List.combine} but tail-recursive.
|
||||
@raise Invalid_argument if the lists have distinct lengths.
|
||||
@since NEXT_RELEASE *)
|
||||
|
||||
val combine_gen : 'a list -> 'b list -> ('a * 'b) gen
|
||||
(** 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 NEXT_RELEASE *)
|
||||
|
||||
val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int
|
||||
|
||||
val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
|
||||
|
|
@ -433,12 +451,6 @@ end
|
|||
|
||||
(** {2 Conversions} *)
|
||||
|
||||
type 'a sequence = ('a -> unit) -> unit
|
||||
type 'a gen = unit -> 'a option
|
||||
type 'a klist = unit -> [`Nil | `Cons of 'a * 'a klist]
|
||||
type 'a printer = Format.formatter -> 'a -> unit
|
||||
type 'a random_gen = Random.State.t -> 'a
|
||||
|
||||
val random : 'a random_gen -> 'a t random_gen
|
||||
val random_non_empty : 'a random_gen -> 'a t random_gen
|
||||
val random_len : int -> 'a random_gen -> 'a t random_gen
|
||||
|
|
|
|||
|
|
@ -391,16 +391,7 @@ end
|
|||
let split_on_char c s: _ list =
|
||||
Split.list_cpy ~by:(String.make 1 c) s
|
||||
|
||||
(*$= & ~printer:Q.Print.(list string)
|
||||
["a"; "few"; "words"; "from"; "our"; "sponsors"] \
|
||||
(split_on_char ' ' "a few words from our sponsors")
|
||||
*)
|
||||
|
||||
(*$Q
|
||||
Q.(printable_string) (fun s -> \
|
||||
let s = split_on_char ' ' s |> String.concat " " in \
|
||||
s = split_on_char ' ' s |> String.concat " ")
|
||||
*)
|
||||
let split = Split.list_cpy
|
||||
|
||||
let compare_versions a b =
|
||||
let of_int s = try Some (int_of_string s) with _ -> None in
|
||||
|
|
@ -719,7 +710,16 @@ let lowercase_ascii = map CCChar.lowercase_ascii
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
let equal_caseless s1 s2: bool =
|
||||
let char_lower c =
|
||||
if c >= 'A' && c <= 'Z'
|
||||
then Char.unsafe_chr (Char. code c + 32)
|
||||
else c
|
||||
in
|
||||
String.length s1 = String.length s2 &&
|
||||
for_all2
|
||||
(fun c1 c2 -> char_lower c1 = char_lower c2)
|
||||
s1 s2
|
||||
|
||||
let pp buf s =
|
||||
Buffer.add_char buf '"';
|
||||
|
|
|
|||
|
|
@ -399,6 +399,22 @@ val uppercase_ascii : string -> string
|
|||
val lowercase_ascii : string -> string
|
||||
(** See {!String}. @since 0.18 *)
|
||||
|
||||
val equal_caseless : string -> string -> bool
|
||||
(** Comparison without respect to {b ascii} lowercase.
|
||||
@since NEXT_RELEASE *)
|
||||
|
||||
(*$T
|
||||
equal_caseless "foo" "FoO"
|
||||
equal_caseless "helLo" "HEllO"
|
||||
*)
|
||||
|
||||
(*$Q
|
||||
Q.(pair printable_string printable_string) (fun (s1,s2) -> \
|
||||
equal_caseless s1 s2 = (lowercase_ascii s1=lowercase_ascii s2))
|
||||
Q.(printable_string) (fun s -> equal_caseless s s)
|
||||
Q.(printable_string) (fun s -> equal_caseless (uppercase_ascii s) s)
|
||||
*)
|
||||
|
||||
(** {2 Finding}
|
||||
|
||||
A relatively efficient algorithm for finding sub-strings
|
||||
|
|
@ -499,6 +515,21 @@ val split_on_char : char -> string -> string list
|
|||
(** Split the string along the given char
|
||||
@since NEXT_RELEASE *)
|
||||
|
||||
(*$= & ~printer:Q.Print.(list string)
|
||||
["a"; "few"; "words"; "from"; "our"; "sponsors"] \
|
||||
(split_on_char ' ' "a few words from our sponsors")
|
||||
*)
|
||||
|
||||
(*$Q
|
||||
Q.(printable_string) (fun s -> \
|
||||
let s = split_on_char ' ' s |> String.concat " " in \
|
||||
s = (split_on_char ' ' s |> String.concat " "))
|
||||
*)
|
||||
|
||||
val split : by:string -> string -> string list
|
||||
(** Alias to {!Split.list_cpy}
|
||||
@since NEXT_RELEASE *)
|
||||
|
||||
(** {2 Utils} *)
|
||||
|
||||
val compare_versions : string -> string -> int
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue