From 656565c1957da549ddec6498e640fe9c8e58eb4f Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 22 Aug 2016 10:15:37 +0200 Subject: [PATCH 01/16] add gh-pages doc generation to makefile --- Makefile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Makefile b/Makefile index ed28398b..00dd73da 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,13 @@ examples: all push_doc: doc rsync -tavu containers.docdir/* cedeela.fr:~/simon/root/software/containers/ +push_doc_gh: doc + git checkout gh-pages && \ + rm -rf dev/ && \ + mkdir -p dev && \ + cp -r containers.docdir/* dev/ && \ + git add --all dev + DONTTEST=myocamlbuild.ml setup.ml $(wildcard src/**/*.cppo.*) QTESTABLE=$(filter-out $(DONTTEST), \ $(wildcard src/core/*.ml) \ From 8cd06599aea41e1caa7c291d7a07fec3ba108825 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Mon, 22 Aug 2016 10:21:19 +0200 Subject: [PATCH 02/16] update readme --- README.adoc | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/README.adoc b/README.adoc index b0180351..5028ce5a 100644 --- a/README.adoc +++ b/README.adoc @@ -3,7 +3,7 @@ :source-highlighter: pygments What is _containers_? (take a look at the link:TUTORIAL.adoc[tutorial]! -or the http://cedeela.fr/~simon/software/containers[documentation]) +or the http://cedeela.fr/~simon/software/containers[current documentation]) In `containers` and `containers.data`, all modules abide by _pay for what you use_: only modules that are used are linked (there are no cross-module dependencies). @@ -230,6 +230,18 @@ The library has moved to https://github.com/c-cube/containers-misc . `containers.lwt` has moved to https://github.com/c-cube/containers-lwt . [[build]] + +== Documentation + +In general, see http://c-cube.github.io/ocaml-containers/ or +http://cedeela.fr/~simon/software/containers + +by version: + +- http://c-cube.github.io/ocaml-containers/dev/[dev branch] +- http://c-cube.github.io/ocaml-containers/0.17/[0.17] +- http://c-cube.github.io/ocaml-containers/0.19/[0.19] + == Build You will need OCaml `>=` 4.00.0. @@ -270,7 +282,3 @@ A few guidelines: - add tests if possible (using `qtest`). Powered by image:http://oasis.forge.ocamlcore.org/oasis-badge.png[alt="OASIS", style="border: none;", link="http://oasis.forge.ocamlcore.org/"] - -== Documentation by version - -- http://c-cube.github.io/ocaml-containers/0.17/[0.17] From b249adf86f1e84a23bbfb7af9cce4f25ccf8f147 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sun, 18 Sep 2016 10:33:35 +0200 Subject: [PATCH 03/16] add `CCInt.{print_binary,to_string_binary}` + tests (thanks @gsg) --- AUTHORS.adoc | 1 + src/core/CCInt.ml | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/core/CCInt.mli | 7 +++++++ 3 files changed, 52 insertions(+) diff --git a/AUTHORS.adoc b/AUTHORS.adoc index be70282a..478c46aa 100644 --- a/AUTHORS.adoc +++ b/AUTHORS.adoc @@ -14,3 +14,4 @@ - JP Rodi - octachron (Florian Angeletti) - Johannes Kloos +- Geoff Gole (@gsg) diff --git a/src/core/CCInt.ml b/src/core/CCInt.ml index ba1d82a2..16012426 100644 --- a/src/core/CCInt.ml +++ b/src/core/CCInt.ml @@ -48,12 +48,56 @@ let random_range i j st = i + random (j-i) st let pp buf = Printf.bprintf buf "%d" let print fmt = Format.pp_print_int fmt +let most_significant_bit = + (-1) lxor ((-1) lsr 1) + let to_string = string_of_int let of_string s = try Some (int_of_string s) with _ -> None +type output = char -> unit + +(* abstract printer *) +let to_binary_gen (out:output) n = + let n = if n<0 then (out '-'; -n) else n in + out '0'; out 'b'; + let rec loop started bit n = + if bit = 0 then ( + if not started then out '0' + ) else ( + let b = n land bit in + if b = 0 then ( + if started then out '0'; + loop started (bit lsr 1) n + ) else ( + out '1'; + loop true (bit lsr 1) n + ) + ) + in + loop false most_significant_bit n + +let print_binary out n = + to_binary_gen (Format.pp_print_char out) n + +let to_string_binary n = + let buf = Buffer.create 16 in + to_binary_gen (Buffer.add_char buf) n; + Buffer.contents buf + +(*$= & ~printer:CCFun.id + "0b111" (to_string_binary 7) + "-0b111" (to_string_binary (-7)) + "0b0" (to_string_binary 0) +*) + + +(*$Q & ~count:10_000 + Q.int (fun n -> n = int_of_string (to_string_binary n)) +*) + module Infix = struct let (=) = Pervasives.(=) let (<>) = Pervasives.(<>) diff --git a/src/core/CCInt.mli b/src/core/CCInt.mli index adc77339..c6b116d9 100644 --- a/src/core/CCInt.mli +++ b/src/core/CCInt.mli @@ -40,6 +40,13 @@ val to_string : t -> string val of_string : string -> t option (** @since 0.13 *) +val print_binary : t formatter +(** prints as "0b00101010". + @since NEXT_RELEASE *) + +val to_string_binary : t -> string +(** @since NEXT_RELEASE *) + val min : t -> t -> t (** @since 0.17 *) From 7a823b16d8b39b3f466b35eff10d1cf4576e440f Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sun, 18 Sep 2016 20:31:53 +0200 Subject: [PATCH 04/16] fix `CCString.*_ascii`; add `CCChar.{upper,lower}case_ascii` --- src/core/CCChar.ml | 10 ++++++++++ src/core/CCChar.mli | 8 ++++++++ src/core/CCString.cppo.ml | 18 ++++++++++++++---- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/core/CCChar.ml b/src/core/CCChar.ml index a1622930..460d2eed 100644 --- a/src/core/CCChar.ml +++ b/src/core/CCChar.ml @@ -11,3 +11,13 @@ let compare = Char.compare let pp = Buffer.add_char let print = Format.pp_print_char + +let lowercase_ascii c = + if c >= 'A' && c <= 'Z' + then Char.unsafe_chr (Char. code c + 32) + else c + +let uppercase_ascii c = + if c >= 'a' && c <= 'z' + then Char.unsafe_chr (Char.code c - 32) + else c diff --git a/src/core/CCChar.mli b/src/core/CCChar.mli index 1ca8dcd3..345049b2 100644 --- a/src/core/CCChar.mli +++ b/src/core/CCChar.mli @@ -9,5 +9,13 @@ type t = char val equal : t -> t -> bool val compare : t -> t -> int +val lowercase_ascii : t -> t +(** See {!Char} + @since NEXT_RELEASE *) + +val uppercase_ascii : t -> t +(** See {!Char} + @since NEXT_RELEASE *) + val pp : Buffer.t -> t -> unit val print : Format.formatter -> t -> unit diff --git a/src/core/CCString.cppo.ml b/src/core/CCString.cppo.ml index d29da1e6..61fa8240 100644 --- a/src/core/CCString.cppo.ml +++ b/src/core/CCString.cppo.ml @@ -651,10 +651,20 @@ let lowercase_ascii = String.lowercase_ascii #else -let capitalize_ascii = String.capitalize -let uncapitalize_ascii = String.uncapitalize -let uppercase_ascii = String.uppercase -let lowercase_ascii = String.lowercase +let capitalize_ascii s = + mapi + (fun i c -> if i=0 then CCChar.uppercase_ascii c else c) + s + + +let uncapitalize_ascii s = + mapi + (fun i c -> if i=0 then CCChar.lowercase_ascii c else c) + s + +let uppercase_ascii = map CCChar.uppercase_ascii + +let lowercase_ascii = map CCChar.lowercase_ascii #endif From 3e50420ce8eb83d90a1e9454984dcf847a68f441 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sun, 25 Sep 2016 19:34:05 +0200 Subject: [PATCH 05/16] add `CCList.{head_opt,last_opt}` --- src/core/CCList.ml | 18 ++++++++++++++++++ src/core/CCList.mli | 8 ++++++++ 2 files changed, 26 insertions(+) diff --git a/src/core/CCList.ml b/src/core/CCList.ml index 92c2747d..17a29a04 100644 --- a/src/core/CCList.ml +++ b/src/core/CCList.ml @@ -569,6 +569,24 @@ let last n l = let len = List.length l in if len < n then l else drop (len-n) l +let head_opt = function + | [] -> None + | x::_ -> Some x + +let rec last_opt = function + | [] -> None + | [x] -> Some x + | _ :: tail -> last_opt tail + +(*$= & ~printer:Q.Print.(option int) + (Some 1) (head_opt [1;2;3]) + (Some 1) (head_opt [1]) + None (head_opt []) + (Some 3) (last_opt [1;2;3]) + (Some 1) (last_opt [1]) + None (last_opt []) +*) + let rec find_pred p l = match l with | [] -> None | x :: _ when p x -> Some x diff --git a/src/core/CCList.mli b/src/core/CCList.mli index a3a35b26..3331b9a7 100644 --- a/src/core/CCList.mli +++ b/src/core/CCList.mli @@ -134,6 +134,14 @@ val last : int -> 'a t -> 'a t (** [last n l] takes the last [n] elements of [l] (or less if [l] doesn't have that many elements *) +val head_opt : 'a t -> 'a option +(** First element. + @since NEXT_RELEASE *) + +val last_opt : 'a t -> 'a option +(** Last element. + @since NEXT_RELEASE *) + val find_pred : ('a -> bool) -> 'a t -> 'a option (** [find_pred p l] finds the first element of [l] that satisfies [p], or returns [None] if no element satisfies [p] From e4c6752b6b4b60a5b190bae3e3ec439de6a98eab Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sun, 25 Sep 2016 19:38:03 +0200 Subject: [PATCH 06/16] add `CCVector.append_gen` --- src/core/CCVector.ml | 14 ++++++++++++++ src/core/CCVector.mli | 4 ++++ 2 files changed, 18 insertions(+) diff --git a/src/core/CCVector.ml b/src/core/CCVector.ml index 40296609..240774fe 100644 --- a/src/core/CCVector.ml +++ b/src/core/CCVector.ml @@ -226,6 +226,20 @@ let append_list a b = match b with length v = List.length l1 + List.length l2) *) +let rec append_gen a b = match b() with + | None -> () + | Some x -> push a x; append_gen a b + +(*$Q + Q.(pair (list int)(list int)) (fun (l1,l2) -> \ + let v = of_list l1 in append_gen v (Gen.of_list l2); \ + to_list v = (l1 @ l2)) + Q.(pair (list int)(list int)) (fun (l1,l2) -> \ + let v = of_list l1 in append_gen v (Gen.of_list l2); \ + length v = List.length l1 + List.length l2) +*) + + (*$inject let gen x = let small = length in diff --git a/src/core/CCVector.mli b/src/core/CCVector.mli index e3a329cd..11dfdee6 100644 --- a/src/core/CCVector.mli +++ b/src/core/CCVector.mli @@ -84,6 +84,10 @@ val append_list : ('a, rw) t -> 'a list -> unit (** Append content of list @since 0.14 *) +val append_gen : ('a, rw) t -> 'a gen -> unit +(** Append content of generator + @since NEXT_RELEASE *) + val equal : 'a equal -> ('a,_) t equal val compare : 'a ord -> ('a,_) t ord From 103963dc4576b9e33d69a4cd3e58350ff14421ad Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sun, 25 Sep 2016 19:39:02 +0200 Subject: [PATCH 07/16] style --- src/core/CCFloat.mli | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/CCFloat.mli b/src/core/CCFloat.mli index 5b47483b..a2e423f2 100644 --- a/src/core/CCFloat.mli +++ b/src/core/CCFloat.mli @@ -19,7 +19,7 @@ val min_value : t val max_finite_value : t -val epsilon : float +val epsilon : t val is_nan : t -> bool @@ -39,7 +39,7 @@ val max : t -> t -> t val equal : t -> t -> bool -val compare : float -> float -> int +val compare : t -> t -> int type 'a printer = Buffer.t -> 'a -> unit type 'a formatter = Format.formatter -> 'a -> unit @@ -54,7 +54,7 @@ val random : t -> t random_gen val random_small : t random_gen val random_range : t -> t -> t random_gen -val fsign : t -> float +val fsign : t -> t (** [fsign x] is one of [-1., -0., +0., +1.], or [nan] if [x] is NaN. @since 0.7 *) @@ -75,7 +75,7 @@ val of_string : string -> t val equal_precision : epsilon:t -> t -> t -> bool (** Equality with allowed error up to a non negative epsilon value *) -val classify : float -> fpclass +val classify : t -> fpclass (** {2 Infix Operators} From d7e8cb24fd65b81370c5b0eaa3f8778a3d0ec119 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Sun, 25 Sep 2016 19:43:21 +0200 Subject: [PATCH 08/16] add `CCFloat.round` --- src/core/CCFloat.ml | 11 +++++++++++ src/core/CCFloat.mli | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/src/core/CCFloat.ml b/src/core/CCFloat.ml index 2fbbe071..0d73342d 100644 --- a/src/core/CCFloat.ml +++ b/src/core/CCFloat.ml @@ -60,6 +60,17 @@ let sign_exn (a:float) = if is_nan a then raise (TrapNaN "sign_exn") else compare a 0. +let round x = + let low = floor x in + let high = ceil x in + if x-.low > high-.x then high else low + +(*$= + 2. (round 1.6) + 1. (round 1.4) + 0. (round 0.) +*) + let to_int (a:float) = Pervasives.int_of_float a let of_int (a:int) = Pervasives.float_of_int a diff --git a/src/core/CCFloat.mli b/src/core/CCFloat.mli index a2e423f2..538d2068 100644 --- a/src/core/CCFloat.mli +++ b/src/core/CCFloat.mli @@ -58,6 +58,10 @@ val fsign : t -> t (** [fsign x] is one of [-1., -0., +0., +1.], or [nan] if [x] is NaN. @since 0.7 *) +val round : t -> t +(** [round f] returns the closest integer value, either above or below + @since NEXT_RELEASE *) + exception TrapNaN of string val sign_exn : t -> int (** [sign_exn x] will return the sign of [x] as [1, 0] or [-1], or raise an From d4d22b14889d258d8d979c8e0042b0357641c971 Mon Sep 17 00:00:00 2001 From: Roma Sokolov Date: Tue, 4 Oct 2016 14:27:34 +0300 Subject: [PATCH 09/16] Fixes map_or ~default arg for `map_or`, as well as function, should not depend on the type of error case. --- src/core/CCResult.mli | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/CCResult.mli b/src/core/CCResult.mli index 9a1dedc2..fb764167 100644 --- a/src/core/CCResult.mli +++ b/src/core/CCResult.mli @@ -67,7 +67,7 @@ val get_exn : ('a, _) t -> 'a val get_or : ('a, _) t -> default:'a -> 'a (** [get_or e ~default] returns [x] if [e = Ok x], [default] otherwise *) -val map_or : ('a -> 'b) -> ('a, 'b) t -> default:'b -> 'b +val map_or : ('a -> 'b) -> ('a, 'c) t -> default:'b -> 'b (** [map_or f e ~default] returns [f x] if [e = Ok x], [default] otherwise *) val catch : ('a, 'err) t -> ok:('a -> 'b) -> err:('err -> 'b) -> 'b From f0381ae0d928d98900938bc9e378d2636585fc84 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Tue, 4 Oct 2016 13:35:46 +0200 Subject: [PATCH 10/16] update `authors` --- AUTHORS.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS.adoc b/AUTHORS.adoc index 478c46aa..de89cd30 100644 --- a/AUTHORS.adoc +++ b/AUTHORS.adoc @@ -12,6 +12,7 @@ - Emmanuel Surleau (emm) - Guillaume Bury (guigui) - JP Rodi -- octachron (Florian Angeletti) +- Florian Angeletti (@octachron) - Johannes Kloos - Geoff Gole (@gsg) +- Roma Sokolov (@little-arhat) From a99720945b2a4627f12d6248b2d5b2da13dfaf5f Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Thu, 13 Oct 2016 10:01:21 +0200 Subject: [PATCH 11/16] add `CCArray.rev` --- src/core/CCArray.ml | 15 +++++++++++++++ src/core/CCArray.mli | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/src/core/CCArray.ml b/src/core/CCArray.ml index a7230a77..7c38eb45 100644 --- a/src/core/CCArray.ml +++ b/src/core/CCArray.ml @@ -350,6 +350,21 @@ let reverse_in_place a = a = [| 6;5;4;3;2;1 |] *) +let rev a = + let b = Array.copy a in + reverse_in_place b; + b + +(*$Q + Q.(array small_int) (fun a -> rev (rev a) = a) +*) + +(*$T + rev [| 1; 2; 3 |] = [| 3; 2; 1 |] + rev [| 1; 2; |] = [| 2; 1 |] + rev [| |] = [| |] + *) + let find f a = _find (fun _ -> f ) a 0 (Array.length a) diff --git a/src/core/CCArray.mli b/src/core/CCArray.mli index eb6b9d29..fd7eb5bb 100644 --- a/src/core/CCArray.mli +++ b/src/core/CCArray.mli @@ -143,6 +143,10 @@ include S with type 'a t := 'a t val map : ('a -> 'b) -> 'a t -> 'b t +val rev : 'a t -> 'a t +(** Copy + reverse in place + @since NEXT_RELEASE *) + val filter : ('a -> bool) -> 'a t -> 'a t (** Filter elements out of the array. Only the elements satisfying the given predicate will be kept. *) From 53030c4c29239d3b422cc66dbd296573ef1d0a98 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Thu, 13 Oct 2016 10:04:23 +0200 Subject: [PATCH 12/16] more general types for `CCArray.{for_all2,exists2}` --- src/core/CCArray.ml | 10 ++++++---- src/core/CCArray.mli | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/core/CCArray.ml b/src/core/CCArray.ml index 7c38eb45..4890a9a3 100644 --- a/src/core/CCArray.ml +++ b/src/core/CCArray.ml @@ -94,15 +94,17 @@ module type S = sig val for_all : ('a -> bool) -> 'a t -> bool - val for_all2 : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool + val for_all2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool (** Forall on pairs of arrays. - @raise Invalid_argument if they have distinct lengths *) + @raise Invalid_argument if they have distinct lengths + allow different types @since NEXT_RELEASE *) val exists : ('a -> bool) -> 'a t -> bool - val exists2 : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool + val exists2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool (** Exists on pairs of arrays. - @raise Invalid_argument if they have distinct lengths *) + @raise Invalid_argument if they have distinct lengths + allow different types @since NEXT_RELEASE *) val shuffle : 'a t -> unit (** shuffle randomly the array, in place *) diff --git a/src/core/CCArray.mli b/src/core/CCArray.mli index fd7eb5bb..6b417c51 100644 --- a/src/core/CCArray.mli +++ b/src/core/CCArray.mli @@ -96,15 +96,17 @@ module type S = sig val for_all : ('a -> bool) -> 'a t -> bool - val for_all2 : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool + val for_all2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool (** Forall on pairs of arrays. - @raise Invalid_argument if they have distinct lengths *) + @raise Invalid_argument if they have distinct lengths + allow different types @since NEXT_RELEASE *) val exists : ('a -> bool) -> 'a t -> bool - val exists2 : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool + val exists2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool (** Exists on pairs of arrays. - @raise Invalid_argument if they have distinct lengths *) + @raise Invalid_argument if they have distinct lengths + allow different types @since NEXT_RELEASE *) val shuffle : 'a t -> unit (** Shuffle randomly the array, in place *) From fed7dd41e063454883cd6eaee83bf894de00796a Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Thu, 13 Oct 2016 10:04:58 +0200 Subject: [PATCH 13/16] add functions in `CCArray`: fold2,iter2,map2 --- src/core/CCArray.ml | 52 ++++++++++++++++++++++++++++++++++++++++---- src/core/CCArray.mli | 15 +++++++++++++ 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/core/CCArray.ml b/src/core/CCArray.ml index 4890a9a3..6daf0f08 100644 --- a/src/core/CCArray.ml +++ b/src/core/CCArray.ml @@ -106,8 +106,18 @@ module type S = sig @raise Invalid_argument if they have distinct lengths allow different types @since NEXT_RELEASE *) + val fold2 : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> 'a t -> 'b t -> 'acc + (** Fold on two arrays stepwise. + @raise Invalid_argument if they have distinct lengths + @since NEXT_RELEASE *) + + val iter2 : ('a -> 'b -> unit) -> 'a t -> 'b t -> unit + (** Iterate on two arrays stepwise. + @raise Invalid_argument if they have distinct lengths + @since NEXT_RELEASE *) + val shuffle : 'a t -> unit - (** shuffle randomly the array, in place *) + (** Shuffle randomly the array, in place *) val shuffle_with : Random.State.t -> 'a t -> unit (** Like shuffle but using a specialized random state *) @@ -124,15 +134,15 @@ module type S = sig val pp: ?sep:string -> (Buffer.t -> 'a -> unit) -> Buffer.t -> 'a t -> unit - (** print an array of items with printing function *) + (** Print an array of items with printing function *) val pp_i: ?sep:string -> (Buffer.t -> int -> 'a -> unit) -> Buffer.t -> 'a t -> unit - (** print an array, giving the printing function both index and item *) + (** Print an array, giving the printing function both index and item *) val print : ?sep:string -> (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a t -> unit - (** print an array of items with printing function *) + (** Print an array of items with printing function *) end (** {2 General Implementation} @@ -293,6 +303,10 @@ let empty = [| |] let map = Array.map +let map2 f a b = + if Array.length a <> Array.length b then invalid_arg "map2"; + Array.init (Array.length a) (fun i -> f (Array.unsafe_get a i) (Array.unsafe_get b i)) + let length = Array.length let get = Array.get @@ -472,6 +486,28 @@ let for_all2 p a b = let exists2 p a b = _exists2 p a b 0 0 ~len:(min (Array.length a) (Array.length b)) +let _iter2 f a b i j ~len = + for o = 0 to len-1 do + f (Array.get a (i+o)) (Array.get b (j+o)) + done + +let _fold2 f acc a b i j ~len = + let rec aux acc o = + if o=len then acc + else + let acc = f acc (Array.get a (i+o)) (Array.get b (j+o)) in + aux acc (o+1) + in + aux acc 0 + +let iter2 f a b = + if length a <> length b then invalid_arg "iter2"; + _iter2 f a b 0 0 ~len:(Array.length a) + +let fold2 f acc a b = + if length a <> length b then invalid_arg "fold2"; + _fold2 f acc a b 0 0 ~len:(Array.length a) + let (--) i j = if i<=j then @@ -675,6 +711,14 @@ module Sub = struct Sub.exists2 (=) (Sub.make [| 1;2;3;4 |] 1 ~len:2) (Sub.make [| 0;1;3;4 |] 1 ~len:3) *) + let iter2 f a b = + if length a <> length b then invalid_arg "iter2"; + _iter2 f a.arr b.arr a.i b.i ~len:(length a) + + let fold2 f acc a b = + if length a <> length b then invalid_arg "fold2"; + _fold2 f acc a.arr b.arr a.i b.i ~len:(length a) + let shuffle a = _shuffle Random.int a.arr a.i a.j diff --git a/src/core/CCArray.mli b/src/core/CCArray.mli index 6b417c51..24be5897 100644 --- a/src/core/CCArray.mli +++ b/src/core/CCArray.mli @@ -108,6 +108,16 @@ module type S = sig @raise Invalid_argument if they have distinct lengths allow different types @since NEXT_RELEASE *) + val fold2 : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> 'a t -> 'b t -> 'acc + (** Fold on two arrays stepwise. + @raise Invalid_argument if they have distinct lengths + @since NEXT_RELEASE *) + + val iter2 : ('a -> 'b -> unit) -> 'a t -> 'b t -> unit + (** Iterate on two arrays stepwise. + @raise Invalid_argument if they have distinct lengths + @since NEXT_RELEASE *) + val shuffle : 'a t -> unit (** Shuffle randomly the array, in place *) @@ -145,6 +155,11 @@ include S with type 'a t := 'a t val map : ('a -> 'b) -> 'a t -> 'b t +val map2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t +(** Map on two arrays stepwise. + @raise Invalid_argument if they have distinct lengths + @since NEXT_RELEASE *) + val rev : 'a t -> 'a t (** Copy + reverse in place @since NEXT_RELEASE *) From 59a463a882e9c09a56e5a6bed6ee0bae1fcd383b Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 14 Oct 2016 11:23:45 +0200 Subject: [PATCH 14/16] small fix + test --- src/core/CCArray.ml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/CCArray.ml b/src/core/CCArray.ml index 6daf0f08..6ee5e850 100644 --- a/src/core/CCArray.ml +++ b/src/core/CCArray.ml @@ -162,7 +162,7 @@ let _reverse_in_place a i ~len = done let rec _equal eq a1 i1 j1 a2 i2 j2 = - if i1 = j1 || i2 = j2 + if i1 = j1 then (assert (i1=j1 && i2=j2); true) else eq a1.(i1) a2.(i2) && _equal eq a1 (i1+1) j1 a2 (i2+2) j2 @@ -548,6 +548,11 @@ let equal eq a b = && _equal eq a 0 (Array.length a) b 0 (Array.length b) +(*$Q + Q.(pair (array small_int)(array small_int)) (fun (a,b) -> \ + equal (=) a b = equal (=) b a) +*) + let compare cmp a b = _compare cmp a 0 (Array.length a) b 0 (Array.length b) From 81ca239ccc201de313f5ee5b69086af574f8e083 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 14 Oct 2016 11:28:44 +0200 Subject: [PATCH 15/16] bugfix in CCArray.equal --- src/core/CCArray.ml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/CCArray.ml b/src/core/CCArray.ml index 6ee5e850..9b179414 100644 --- a/src/core/CCArray.ml +++ b/src/core/CCArray.ml @@ -165,7 +165,7 @@ let rec _equal eq a1 i1 j1 a2 i2 j2 = if i1 = j1 then (assert (i1=j1 && i2=j2); true) else - eq a1.(i1) a2.(i2) && _equal eq a1 (i1+1) j1 a2 (i2+2) j2 + eq a1.(i1) a2.(i2) && _equal eq a1 (i1+1) j1 a2 (i2+1) j2 let rec _compare cmp a1 i1 j1 a2 i2 j2 = if i1 = j1 @@ -553,6 +553,10 @@ let equal eq a b = equal (=) a b = equal (=) b a) *) +(*$T + equal (=) [|1|] [|1|] +*) + let compare cmp a b = _compare cmp a 0 (Array.length a) b 0 (Array.length b) From bc7967054f5e2d28ec29f277284d4a017d58bdcb Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Fri, 14 Oct 2016 11:33:53 +0200 Subject: [PATCH 16/16] prepare for 0.20 --- CHANGELOG.adoc | 14 ++++++++++++++ _oasis | 4 ++-- src/core/CCArray.ml | 8 ++++---- src/core/CCArray.mli | 12 ++++++------ src/core/CCChar.mli | 4 ++-- src/core/CCFloat.mli | 2 +- src/core/CCInt.mli | 4 ++-- src/core/CCList.mli | 4 ++-- src/core/CCVector.mli | 2 +- 9 files changed, 34 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 2f2ab89f..506ae9df 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -1,5 +1,19 @@ = Changelog +== 0.20 + +- bugfix in `CCArray.equal` +- fix `CCString.*_ascii`; add `CCChar.{upper,lower}case_ascii` + +- add functions in `CCArray`: fold2,iter2,map2 +- add `CCArray.rev` +- add `CCFloat.round` +- add `CCVector.append_gen` +- add `CCList.{head_opt,last_opt}` +- add `CCInt.{print_binary,to_string_binary}` + tests (thanks @gsg) +- more general types for `CCArray.{for_all2,exists2}` +- more general type for `CCResult.map_or` + == 0.19 - add regression test for #75 diff --git a/_oasis b/_oasis index 6a4e3702..2ea5ba5d 100644 --- a/_oasis +++ b/_oasis @@ -1,6 +1,6 @@ OASISFormat: 0.4 Name: containers -Version: 0.19 +Version: 0.20 Homepage: https://github.com/c-cube/ocaml-containers Authors: Simon Cruanes License: BSD-2-clause @@ -179,7 +179,7 @@ Executable run_qtest containers.io, containers.advanced, containers.sexp, containers.bigarray, containers.unix, containers.thread, containers.data, - sequence, gen, unix, oUnit, qcheck + sequence, gen, unix, oUnit, qcheck Test all Command: ./run_qtest.native diff --git a/src/core/CCArray.ml b/src/core/CCArray.ml index 9b179414..cc7b622f 100644 --- a/src/core/CCArray.ml +++ b/src/core/CCArray.ml @@ -97,24 +97,24 @@ module type S = sig val for_all2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool (** Forall on pairs of arrays. @raise Invalid_argument if they have distinct lengths - allow different types @since NEXT_RELEASE *) + allow different types @since 0.20 *) val exists : ('a -> bool) -> 'a t -> bool val exists2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool (** Exists on pairs of arrays. @raise Invalid_argument if they have distinct lengths - allow different types @since NEXT_RELEASE *) + allow different types @since 0.20 *) val fold2 : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> 'a t -> 'b t -> 'acc (** Fold on two arrays stepwise. @raise Invalid_argument if they have distinct lengths - @since NEXT_RELEASE *) + @since 0.20 *) val iter2 : ('a -> 'b -> unit) -> 'a t -> 'b t -> unit (** Iterate on two arrays stepwise. @raise Invalid_argument if they have distinct lengths - @since NEXT_RELEASE *) + @since 0.20 *) val shuffle : 'a t -> unit (** Shuffle randomly the array, in place *) diff --git a/src/core/CCArray.mli b/src/core/CCArray.mli index 24be5897..8206d2cb 100644 --- a/src/core/CCArray.mli +++ b/src/core/CCArray.mli @@ -99,24 +99,24 @@ module type S = sig val for_all2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool (** Forall on pairs of arrays. @raise Invalid_argument if they have distinct lengths - allow different types @since NEXT_RELEASE *) + allow different types @since 0.20 *) val exists : ('a -> bool) -> 'a t -> bool val exists2 : ('a -> 'b -> bool) -> 'a t -> 'b t -> bool (** Exists on pairs of arrays. @raise Invalid_argument if they have distinct lengths - allow different types @since NEXT_RELEASE *) + allow different types @since 0.20 *) val fold2 : ('acc -> 'a -> 'b -> 'acc) -> 'acc -> 'a t -> 'b t -> 'acc (** Fold on two arrays stepwise. @raise Invalid_argument if they have distinct lengths - @since NEXT_RELEASE *) + @since 0.20 *) val iter2 : ('a -> 'b -> unit) -> 'a t -> 'b t -> unit (** Iterate on two arrays stepwise. @raise Invalid_argument if they have distinct lengths - @since NEXT_RELEASE *) + @since 0.20 *) val shuffle : 'a t -> unit (** Shuffle randomly the array, in place *) @@ -158,11 +158,11 @@ val map : ('a -> 'b) -> 'a t -> 'b t val map2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t (** Map on two arrays stepwise. @raise Invalid_argument if they have distinct lengths - @since NEXT_RELEASE *) + @since 0.20 *) val rev : 'a t -> 'a t (** Copy + reverse in place - @since NEXT_RELEASE *) + @since 0.20 *) val filter : ('a -> bool) -> 'a t -> 'a t (** Filter elements out of the array. Only the elements satisfying diff --git a/src/core/CCChar.mli b/src/core/CCChar.mli index 345049b2..748ab659 100644 --- a/src/core/CCChar.mli +++ b/src/core/CCChar.mli @@ -11,11 +11,11 @@ val compare : t -> t -> int val lowercase_ascii : t -> t (** See {!Char} - @since NEXT_RELEASE *) + @since 0.20 *) val uppercase_ascii : t -> t (** See {!Char} - @since NEXT_RELEASE *) + @since 0.20 *) val pp : Buffer.t -> t -> unit val print : Format.formatter -> t -> unit diff --git a/src/core/CCFloat.mli b/src/core/CCFloat.mli index 538d2068..766027ac 100644 --- a/src/core/CCFloat.mli +++ b/src/core/CCFloat.mli @@ -60,7 +60,7 @@ val fsign : t -> t val round : t -> t (** [round f] returns the closest integer value, either above or below - @since NEXT_RELEASE *) + @since 0.20 *) exception TrapNaN of string val sign_exn : t -> int diff --git a/src/core/CCInt.mli b/src/core/CCInt.mli index c6b116d9..7657a315 100644 --- a/src/core/CCInt.mli +++ b/src/core/CCInt.mli @@ -42,10 +42,10 @@ val of_string : string -> t option val print_binary : t formatter (** prints as "0b00101010". - @since NEXT_RELEASE *) + @since 0.20 *) val to_string_binary : t -> string -(** @since NEXT_RELEASE *) +(** @since 0.20 *) val min : t -> t -> t (** @since 0.17 *) diff --git a/src/core/CCList.mli b/src/core/CCList.mli index 3331b9a7..93df4694 100644 --- a/src/core/CCList.mli +++ b/src/core/CCList.mli @@ -136,11 +136,11 @@ val last : int -> 'a t -> 'a t val head_opt : 'a t -> 'a option (** First element. - @since NEXT_RELEASE *) + @since 0.20 *) val last_opt : 'a t -> 'a option (** Last element. - @since NEXT_RELEASE *) + @since 0.20 *) val find_pred : ('a -> bool) -> 'a t -> 'a option (** [find_pred p l] finds the first element of [l] that satisfies [p], diff --git a/src/core/CCVector.mli b/src/core/CCVector.mli index 11dfdee6..ad47b070 100644 --- a/src/core/CCVector.mli +++ b/src/core/CCVector.mli @@ -86,7 +86,7 @@ val append_list : ('a, rw) t -> 'a list -> unit val append_gen : ('a, rw) t -> 'a gen -> unit (** Append content of generator - @since NEXT_RELEASE *) + @since 0.20 *) val equal : 'a equal -> ('a,_) t equal