Merge branch 'master' into stable

This commit is contained in:
Simon Cruanes 2016-10-14 11:34:02 +02:00
commit f6774434cd
19 changed files with 291 additions and 31 deletions

View file

@ -12,5 +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)

View file

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

View file

@ -50,6 +50,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) \

View file

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

2
_oasis
View file

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

View file

@ -94,18 +94,30 @@ 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 0.20 *)
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 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 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 0.20 *)
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 *)
@ -122,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}
@ -150,10 +162,10 @@ 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
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
@ -291,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
@ -350,6 +366,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)
@ -455,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
@ -495,6 +548,15 @@ 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)
*)
(*$T
equal (=) [|1|] [|1|]
*)
let compare cmp a b =
_compare cmp a 0 (Array.length a) b 0 (Array.length b)
@ -658,6 +720,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

View file

@ -96,15 +96,27 @@ 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 0.20 *)
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 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 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 0.20 *)
val shuffle : 'a t -> unit
(** Shuffle randomly the array, in place *)
@ -143,6 +155,15 @@ 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 0.20 *)
val rev : 'a t -> 'a t
(** Copy + reverse in place
@since 0.20 *)
val filter : ('a -> bool) -> 'a t -> 'a t
(** Filter elements out of the array. Only the elements satisfying
the given predicate will be kept. *)

View file

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

View file

@ -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 0.20 *)
val uppercase_ascii : t -> t
(** See {!Char}
@since 0.20 *)
val pp : Buffer.t -> t -> unit
val print : Format.formatter -> t -> unit

View file

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

View file

@ -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,10 +54,14 @@ 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 *)
val round : t -> t
(** [round f] returns the closest integer value, either above or below
@since 0.20 *)
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
@ -75,7 +79,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}

View file

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

View file

@ -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 0.20 *)
val to_string_binary : t -> string
(** @since 0.20 *)
val min : t -> t -> t
(** @since 0.17 *)

View file

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

View file

@ -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 0.20 *)
val last_opt : 'a t -> 'a option
(** Last element.
@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],
or returns [None] if no element satisfies [p]

View file

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

View file

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

View file

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

View file

@ -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 0.20 *)
val equal : 'a equal -> ('a,_) t equal
val compare : 'a ord -> ('a,_) t ord