Merge branch 'master' into add_negate

This commit is contained in:
Leonid Rozenberg 2017-04-19 12:30:35 -04:00 committed by GitHub
commit cbff4e5a39
7 changed files with 165 additions and 18 deletions

View file

@ -19,4 +19,5 @@
- Malcolm Matalka (`orbitz`)
- David Sheets (@dsheets)
- Glenn Slotte (glennsl)
- @LemonBoy
- Leonid Rozenberg (@rleonid)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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