Merge branch 'master' into stable for 0.18

This commit is contained in:
Simon Cruanes 2016-06-14 14:12:54 +02:00
commit ed2b741865
27 changed files with 490 additions and 61 deletions

View file

@ -1,8 +1,19 @@
= Changelog = Changelog
== 0.18
- update implem of `CCVector.equal`
- add `CCOpt.get_or` with label, deprecates `get`
- add `CCArray.get_safe` (close #70)
- add `CCGraph.is_dag`
- add aliases to deprecated functions from `String`, add `Fun.opaque_identity`
- add `CCLazy_list.take`
- add `Lazy_list.filter`
- add CCList.range_by
== 0.17 == 0.17
=== potentially breaking === potentially breaking
- change the semantics of `CCString.find_all` (allow overlaps) - change the semantics of `CCString.find_all` (allow overlaps)

View file

@ -16,7 +16,8 @@ can be removed.
8. `git merge master` 8. `git merge master`
9. `oasis setup; make test doc` 9. `oasis setup; make test doc`
10. tag, and push both to github 10. tag, and push both to github
11. new opam package 11. `opam pin https://github.com/c-cube/ocaml-containers#<release>`
12. new opam package: `opam publish prepare; opam publish submit`
== List Authors == List Authors

View file

@ -2,10 +2,11 @@
:toc: macro :toc: macro
:source-highlighter: pygments :source-highlighter: pygments
image::media/logo.png[logo]
What is _containers_? (take a look at the link:TUTORIAL.adoc[tutorial]! 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[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).
- A usable, reasonably well-designed library that extends OCaml's standard - A usable, reasonably well-designed library that extends OCaml's standard
library (in 'src/core/', packaged under `containers` in ocamlfind. Modules library (in 'src/core/', packaged under `containers` in ocamlfind. Modules
@ -42,6 +43,8 @@ image:https://ci.cedeela.fr/buildStatus/icon?job=containers[alt="Build Status",
toc::[] toc::[]
image::media/logo.png[logo]
== Change Log == Change Log
See link:CHANGELOG.adoc[this file]. See link:CHANGELOG.adoc[this file].
@ -268,3 +271,6 @@ A few guidelines:
Powered by image:http://oasis.forge.ocamlcore.org/oasis-badge.png[alt="OASIS", style="border: none;", link="http://oasis.forge.ocamlcore.org/"] 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]

4
_oasis
View file

@ -1,6 +1,6 @@
OASISFormat: 0.4 OASISFormat: 0.4
Name: containers Name: containers
Version: 0.17 Version: 0.18
Homepage: https://github.com/c-cube/ocaml-containers Homepage: https://github.com/c-cube/ocaml-containers
Authors: Simon Cruanes Authors: Simon Cruanes
License: BSD-2-clause License: BSD-2-clause
@ -40,7 +40,7 @@ Flag "bigarray"
Default: true Default: true
Flag "advanced" Flag "advanced"
Description: Build advanced combinators, including CCLinq (requires "sequence") Description: Build advanced combinators (requires "sequence")
Default: true Default: true
Library "containers" Library "containers"

View file

@ -22,6 +22,8 @@ by ocamlfind).
{4 Core Modules (extension of the standard library)} {4 Core Modules (extension of the standard library)}
{b findlib name}: containers
{!modules: {!modules:
CCArray CCArray
CCBool CCBool
@ -63,6 +65,8 @@ such as:
{4 Containers.data} {4 Containers.data}
{b findlib name}: containers.data
Various data structures. Various data structures.
{!modules: {!modules:
@ -123,6 +127,8 @@ CCLazy_list}
{4 String} {4 String}
{b findlib name}: containers.string
{!modules: {!modules:
CCApp_parse CCApp_parse
CCKMP CCKMP
@ -139,6 +145,8 @@ Use bigarrays to hold large strings and map files directly into memory.
{4 Advanced} {4 Advanced}
{b findlib name}: containers.advanced
This module is qualified with [Containers_advanced]. It This module is qualified with [Containers_advanced]. It
requires {{:https://github.com/c-cube/sequence} Sequence}. requires {{:https://github.com/c-cube/sequence} Sequence}.
@ -152,7 +160,11 @@ Moved to its own repository.
Moved to its own repository Moved to its own repository
{4 Others} {4 Thread Helpers}
{b findlib name}: containers.thread
Modules related to the use of [Thread].
{!modules: {!modules:
CCBlockingQueue CCBlockingQueue

View file

@ -1,5 +1,5 @@
(* OASIS_START *) (* OASIS_START *)
(* DO NOT EDIT (digest: b119194f5742ac2f3cdceac9a223dda7) *) (* DO NOT EDIT (digest: 9ba607f1a3e839f1c1e8ea449ddfab16) *)
module OASISGettext = struct module OASISGettext = struct
(* # 22 "src/oasis/OASISGettext.ml" *) (* # 22 "src/oasis/OASISGettext.ml" *)
@ -29,6 +29,166 @@ module OASISGettext = struct
end end
module OASISString = struct
(* # 22 "src/oasis/OASISString.ml" *)
(** Various string utilities.
Mostly inspired by extlib and batteries ExtString and BatString libraries.
@author Sylvain Le Gall
*)
let nsplitf str f =
if str = "" then
[]
else
let buf = Buffer.create 13 in
let lst = ref [] in
let push () =
lst := Buffer.contents buf :: !lst;
Buffer.clear buf
in
let str_len = String.length str in
for i = 0 to str_len - 1 do
if f str.[i] then
push ()
else
Buffer.add_char buf str.[i]
done;
push ();
List.rev !lst
(** [nsplit c s] Split the string [s] at char [c]. It doesn't include the
separator.
*)
let nsplit str c =
nsplitf str ((=) c)
let find ~what ?(offset=0) str =
let what_idx = ref 0 in
let str_idx = ref offset in
while !str_idx < String.length str &&
!what_idx < String.length what do
if str.[!str_idx] = what.[!what_idx] then
incr what_idx
else
what_idx := 0;
incr str_idx
done;
if !what_idx <> String.length what then
raise Not_found
else
!str_idx - !what_idx
let sub_start str len =
let str_len = String.length str in
if len >= str_len then
""
else
String.sub str len (str_len - len)
let sub_end ?(offset=0) str len =
let str_len = String.length str in
if len >= str_len then
""
else
String.sub str 0 (str_len - len)
let starts_with ~what ?(offset=0) str =
let what_idx = ref 0 in
let str_idx = ref offset in
let ok = ref true in
while !ok &&
!str_idx < String.length str &&
!what_idx < String.length what do
if str.[!str_idx] = what.[!what_idx] then
incr what_idx
else
ok := false;
incr str_idx
done;
if !what_idx = String.length what then
true
else
false
let strip_starts_with ~what str =
if starts_with ~what str then
sub_start str (String.length what)
else
raise Not_found
let ends_with ~what ?(offset=0) str =
let what_idx = ref ((String.length what) - 1) in
let str_idx = ref ((String.length str) - 1) in
let ok = ref true in
while !ok &&
offset <= !str_idx &&
0 <= !what_idx do
if str.[!str_idx] = what.[!what_idx] then
decr what_idx
else
ok := false;
decr str_idx
done;
if !what_idx = -1 then
true
else
false
let strip_ends_with ~what str =
if ends_with ~what str then
sub_end str (String.length what)
else
raise Not_found
let replace_chars f s =
let buf = Buffer.create (String.length s) in
String.iter (fun c -> Buffer.add_char buf (f c)) s;
Buffer.contents buf
let lowercase_ascii =
replace_chars
(fun c ->
if (c >= 'A' && c <= 'Z') then
Char.chr (Char.code c + 32)
else
c)
let uncapitalize_ascii s =
if s <> "" then
(lowercase_ascii (String.sub s 0 1)) ^ (String.sub s 1 ((String.length s) - 1))
else
s
let uppercase_ascii =
replace_chars
(fun c ->
if (c >= 'a' && c <= 'z') then
Char.chr (Char.code c - 32)
else
c)
let capitalize_ascii s =
if s <> "" then
(uppercase_ascii (String.sub s 0 1)) ^ (String.sub s 1 ((String.length s) - 1))
else
s
end
module OASISExpr = struct module OASISExpr = struct
(* # 22 "src/oasis/OASISExpr.ml" *) (* # 22 "src/oasis/OASISExpr.ml" *)
@ -129,7 +289,7 @@ module OASISExpr = struct
end end
# 132 "myocamlbuild.ml" # 292 "myocamlbuild.ml"
module BaseEnvLight = struct module BaseEnvLight = struct
(* # 22 "src/base/BaseEnvLight.ml" *) (* # 22 "src/base/BaseEnvLight.ml" *)
@ -234,7 +394,7 @@ module BaseEnvLight = struct
end end
# 237 "myocamlbuild.ml" # 397 "myocamlbuild.ml"
module MyOCamlbuildFindlib = struct module MyOCamlbuildFindlib = struct
(* # 22 "src/plugins/ocamlbuild/MyOCamlbuildFindlib.ml" *) (* # 22 "src/plugins/ocamlbuild/MyOCamlbuildFindlib.ml" *)
@ -516,7 +676,7 @@ module MyOCamlbuildBase = struct
| nm, [], intf_modules -> | nm, [], intf_modules ->
ocaml_lib nm; ocaml_lib nm;
let cmis = let cmis =
List.map (fun m -> (String.uncapitalize m) ^ ".cmi") List.map (fun m -> (OASISString.uncapitalize_ascii m) ^ ".cmi")
intf_modules in intf_modules in
dep ["ocaml"; "link"; "library"; "file:"^nm^".cma"] cmis dep ["ocaml"; "link"; "library"; "file:"^nm^".cma"] cmis
| nm, dir :: tl, intf_modules -> | nm, dir :: tl, intf_modules ->
@ -529,7 +689,7 @@ module MyOCamlbuildBase = struct
["compile"; "infer_interface"; "doc"]) ["compile"; "infer_interface"; "doc"])
tl; tl;
let cmis = let cmis =
List.map (fun m -> dir^"/"^(String.uncapitalize m)^".cmi") List.map (fun m -> dir^"/"^(OASISString.uncapitalize_ascii m)^".cmi")
intf_modules in intf_modules in
dep ["ocaml"; "link"; "library"; "file:"^dir^"/"^nm^".cma"] dep ["ocaml"; "link"; "library"; "file:"^dir^"/"^nm^".cma"]
cmis) cmis)
@ -603,7 +763,7 @@ module MyOCamlbuildBase = struct
end end
# 606 "myocamlbuild.ml" # 766 "myocamlbuild.ml"
open Ocamlbuild_plugin;; open Ocamlbuild_plugin;;
let package_default = let package_default =
{ {
@ -669,7 +829,7 @@ let conf = {MyOCamlbuildFindlib.no_automatic_syntax = false}
let dispatch_default = MyOCamlbuildBase.dispatch_default conf package_default;; let dispatch_default = MyOCamlbuildBase.dispatch_default conf package_default;;
# 673 "myocamlbuild.ml" # 833 "myocamlbuild.ml"
(* OASIS_STOP *) (* OASIS_STOP *)
let doc_intro = "doc/intro.txt" ;; let doc_intro = "doc/intro.txt" ;;

1
opam
View file

@ -26,6 +26,7 @@ remove: [
] ]
depends: [ depends: [
"ocamlfind" {build} "ocamlfind" {build}
"oasis" {build}
"base-bytes" "base-bytes"
"result" "result"
"cppo" {build} "cppo" {build}

View file

@ -1,9 +1,9 @@
(* setup.ml generated for the first time by OASIS v0.4.4 *) (* setup.ml generated for the first time by OASIS v0.4.4 *)
(* OASIS_START *) (* OASIS_START *)
(* DO NOT EDIT (digest: 93504d34b391fe80e66c77fd2e99f4e0) *) (* DO NOT EDIT (digest: 935c9eb827a9a1a9b4de988f1afb58dd) *)
(* (*
Regenerated by OASIS v0.4.5 Regenerated by OASIS v0.4.6
Visit http://oasis.forge.ocamlcore.org for more information and Visit http://oasis.forge.ocamlcore.org for more information and
documentation about functions used in this file. documentation about functions used in this file.
*) *)
@ -246,6 +246,33 @@ module OASISString = struct
String.iter (fun c -> Buffer.add_char buf (f c)) s; String.iter (fun c -> Buffer.add_char buf (f c)) s;
Buffer.contents buf Buffer.contents buf
let lowercase_ascii =
replace_chars
(fun c ->
if (c >= 'A' && c <= 'Z') then
Char.chr (Char.code c + 32)
else
c)
let uncapitalize_ascii s =
if s <> "" then
(lowercase_ascii (String.sub s 0 1)) ^ (String.sub s 1 ((String.length s) - 1))
else
s
let uppercase_ascii =
replace_chars
(fun c ->
if (c >= 'a' && c <= 'z') then
Char.chr (Char.code c - 32)
else
c)
let capitalize_ascii s =
if s <> "" then
(uppercase_ascii (String.sub s 0 1)) ^ (String.sub s 1 ((String.length s) - 1))
else
s
end end
@ -315,19 +342,15 @@ module OASISUtils = struct
let compare_csl s1 s2 = let compare_csl s1 s2 =
String.compare (String.lowercase s1) (String.lowercase s2) String.compare (OASISString.lowercase_ascii s1) (OASISString.lowercase_ascii s2)
module HashStringCsl = module HashStringCsl =
Hashtbl.Make Hashtbl.Make
(struct (struct
type t = string type t = string
let equal s1 s2 = (compare_csl s1 s2) = 0
let equal s1 s2 = let hash s = Hashtbl.hash (OASISString.lowercase_ascii s)
(String.lowercase s1) = (String.lowercase s2)
let hash s =
Hashtbl.hash (String.lowercase s)
end) end)
module SetStringCsl = module SetStringCsl =
@ -365,7 +388,7 @@ module OASISUtils = struct
else else
buf buf
in in
String.lowercase buf OASISString.lowercase_ascii buf
end end
@ -471,7 +494,7 @@ module PropList = struct
order = Queue.create (); order = Queue.create ();
name_norm = name_norm =
(if case_insensitive then (if case_insensitive then
String.lowercase OASISString.lowercase_ascii
else else
fun s -> s); fun s -> s);
} }
@ -1822,13 +1845,13 @@ module OASISUnixPath = struct
let capitalize_file f = let capitalize_file f =
let dir = dirname f in let dir = dirname f in
let base = basename f in let base = basename f in
concat dir (String.capitalize base) concat dir (OASISString.capitalize_ascii base)
let uncapitalize_file f = let uncapitalize_file f =
let dir = dirname f in let dir = dirname f in
let base = basename f in let base = basename f in
concat dir (String.uncapitalize base) concat dir (OASISString.uncapitalize_ascii base)
end end
@ -2890,7 +2913,7 @@ module OASISFileUtil = struct
end end
# 2893 "setup.ml" # 2916 "setup.ml"
module BaseEnvLight = struct module BaseEnvLight = struct
(* # 22 "src/base/BaseEnvLight.ml" *) (* # 22 "src/base/BaseEnvLight.ml" *)
@ -2995,7 +3018,7 @@ module BaseEnvLight = struct
end end
# 2998 "setup.ml" # 3021 "setup.ml"
module BaseContext = struct module BaseContext = struct
(* # 22 "src/base/BaseContext.ml" *) (* # 22 "src/base/BaseContext.ml" *)
@ -5406,7 +5429,7 @@ module BaseSetup = struct
end end
# 5409 "setup.ml" # 5432 "setup.ml"
module InternalConfigurePlugin = struct module InternalConfigurePlugin = struct
(* # 22 "src/plugins/internal/InternalConfigurePlugin.ml" *) (* # 22 "src/plugins/internal/InternalConfigurePlugin.ml" *)
@ -5845,8 +5868,8 @@ module InternalInstallPlugin = struct
let make_fnames modul sufx = let make_fnames modul sufx =
List.fold_right List.fold_right
begin fun sufx accu -> begin fun sufx accu ->
(String.capitalize modul ^ sufx) :: (OASISString.capitalize_ascii modul ^ sufx) ::
(String.uncapitalize modul ^ sufx) :: (OASISString.uncapitalize_ascii modul ^ sufx) ::
accu accu
end end
sufx sufx
@ -6270,7 +6293,7 @@ module InternalInstallPlugin = struct
end end
# 6273 "setup.ml" # 6296 "setup.ml"
module OCamlbuildCommon = struct module OCamlbuildCommon = struct
(* # 22 "src/plugins/ocamlbuild/OCamlbuildCommon.ml" *) (* # 22 "src/plugins/ocamlbuild/OCamlbuildCommon.ml" *)
@ -6648,7 +6671,7 @@ module OCamlbuildDocPlugin = struct
end end
# 6651 "setup.ml" # 6674 "setup.ml"
module CustomPlugin = struct module CustomPlugin = struct
(* # 22 "src/plugins/custom/CustomPlugin.ml" *) (* # 22 "src/plugins/custom/CustomPlugin.ml" *)
@ -6796,7 +6819,7 @@ module CustomPlugin = struct
end end
# 6799 "setup.ml" # 6822 "setup.ml"
open OASISTypes;; open OASISTypes;;
let setup_t = let setup_t =
@ -6875,7 +6898,7 @@ let setup_t =
alpha_features = ["ocamlbuild_more_args"]; alpha_features = ["ocamlbuild_more_args"];
beta_features = []; beta_features = [];
name = "containers"; name = "containers";
version = "0.17"; version = "0.18";
license = license =
OASISLicense.DEP5License OASISLicense.DEP5License
(OASISLicense.DEP5Unit (OASISLicense.DEP5Unit
@ -6987,7 +7010,7 @@ let setup_t =
{ {
flag_description = flag_description =
Some Some
"Build advanced combinators, including CCLinq (requires \"sequence\")"; "Build advanced combinators (requires \"sequence\")";
flag_default = [(OASISExpr.EBool true, true)] flag_default = [(OASISExpr.EBool true, true)]
}); });
Library Library
@ -7721,8 +7744,9 @@ let setup_t =
plugin_data = [] plugin_data = []
}; };
oasis_fn = Some "_oasis"; oasis_fn = Some "_oasis";
oasis_version = "0.4.5"; oasis_version = "0.4.6";
oasis_digest = Some "\168\138o\130\169\030i2!\170\1730n\148\174\208"; oasis_digest =
Some "\006\139\194\135\189\021\197\018\208\031.\187\212'\016\192";
oasis_exec = None; oasis_exec = None;
oasis_setup_args = []; oasis_setup_args = [];
setup_update = false setup_update = false
@ -7730,6 +7754,6 @@ let setup_t =
let setup () = BaseSetup.setup setup_t;; let setup () = BaseSetup.setup setup_t;;
# 7734 "setup.ml" # 7758 "setup.ml"
(* OASIS_STOP *) (* OASIS_STOP *)
let () = setup ();; let () = setup ();;

View file

@ -33,7 +33,7 @@ Functions and operations are assumed to be referentially transparent, i.e.
they should not rely on external side effects, they should not rely on they should not rely on external side effects, they should not rely on
the order of execution. the order of execution.
@deprecated use {{: https://github.com/c-cube/olinq} OLinq} (once released) @deprecated use {{: https://github.com/c-cube/olinq} OLinq}
{[ {[

View file

@ -22,6 +22,10 @@ module type S = sig
val get : 'a t -> int -> 'a val get : 'a t -> int -> 'a
val get_safe : 'a t -> int -> 'a option
(** [get_safe a i] returns [Some a.(i)] if [i] is a valid index
@since 0.18 *)
val set : 'a t -> int -> 'a -> unit val set : 'a t -> int -> 'a -> unit
val length : _ t -> int val length : _ t -> int
@ -291,6 +295,21 @@ let length = Array.length
let get = Array.get let get = Array.get
let get_safe a i =
if i>=0 && i<Array.length a
then Some (Array.unsafe_get a i)
else None
(*$=
(Some 1) (get_safe [|1;2;3|] 0)
(Some 2) (get_safe [|1;2;3|] 1)
(Some 3) (get_safe [|1;2;3|] 2)
None (get_safe [|1;2;3|] 4)
None (get_safe [|1;2;3|] max_int)
None (get_safe [|1;2;3|] ~-1)
None (get_safe [|1;2;3|] ~-42)
*)
let set = Array.set let set = Array.set
let fold = Array.fold_left let fold = Array.fold_left
@ -568,6 +587,24 @@ module Sub = struct
if i<0 || j>=a.j then invalid_arg "Array.Sub.get"; if i<0 || j>=a.j then invalid_arg "Array.Sub.get";
a.arr.(j) a.arr.(j)
let get_safe a i =
try Some (get a i)
with Invalid_argument _ -> None
(*$inject
let sub_a = Sub.make [|1;2;3;4;5|] 1 ~len:3
*)
(*$=
(Some 2) (Sub.get_safe sub_a 0)
(Some 3) (Sub.get_safe sub_a 1)
(Some 4) (Sub.get_safe sub_a 2)
None (Sub.get_safe sub_a 4)
None (Sub.get_safe sub_a max_int)
None (Sub.get_safe sub_a ~-1)
None (Sub.get_safe sub_a ~-42)
*)
let set a i x = let set a i x =
let j = a.i + i in let j = a.i + i in
if i<0 || j>=a.j then invalid_arg "Array.Sub.set"; if i<0 || j>=a.j then invalid_arg "Array.Sub.set";

View file

@ -24,6 +24,10 @@ module type S = sig
val get : 'a t -> int -> 'a val get : 'a t -> int -> 'a
val get_safe : 'a t -> int -> 'a option
(** [get_safe a i] returns [Some a.(i)] if [i] is a valid index
@since 0.18 *)
val set : 'a t -> int -> 'a -> unit val set : 'a t -> int -> 'a -> unit
val length : _ t -> int val length : _ t -> int

View file

@ -37,6 +37,9 @@ val arrayi : ?start:string -> ?stop:string -> ?sep:string ->
val seq : ?start:string -> ?stop:string -> ?sep:string -> 'a printer -> 'a sequence printer val seq : ?start:string -> ?stop:string -> ?sep:string -> 'a printer -> 'a sequence printer
val opt : 'a printer -> 'a option printer val opt : 'a printer -> 'a option printer
(** [opt pp] prints options as follows:
[Some x] will become "some foo" if [pp x ---> "foo"]
[None] will become "none" *)
(** In the tuple printers, the [sep] argument is only available (** In the tuple printers, the [sep] argument is only available
@since 0.17 *) @since 0.17 *)

View file

@ -15,6 +15,16 @@ let (@@) f x = f x
#endif #endif
#if OCAML_MAJOR >= 4 && OCAML_MINOR >= 3
let opaque_identity = Sys.opaque_identity
#else
let opaque_identity x = x
#endif
let compose f g x = g (f x) let compose f g x = g (f x)
let compose_binop f g x y = g (f x) (f y) let compose_binop f g x y = g (f x) (f y)

View file

@ -65,6 +65,12 @@ val finally2 : h:(unit -> _) -> ('a -> 'b -> 'c) -> 'a -> 'b -> 'c
[h ()] is called whether [f x y] rose an exception or not. [h ()] is called whether [f x y] rose an exception or not.
@since 0.16 *) @since 0.16 *)
val opaque_identity : 'a -> 'a
(** [opaque_identity x] is like [x], but prevents Flambda from using [x]'s
definition for optimizing it (flambda is an optimization/inlining pass
in OCaml >= 4.03).
@since 0.18 *)
(** {2 Monad} (** {2 Monad}
Functions with a fixed domain are monads in their codomain *) Functions with a fixed domain are monads in their codomain *)

View file

@ -792,6 +792,38 @@ module Idx = struct
*) *)
end end
let range_by ~step i j =
let rec range i j acc =
if i=j then i::acc else range i (j-step) (j::acc)
in
if step = 0 then
raise (Invalid_argument "CCList.range_by")
else if (if step > 0 then i>j else i<j) then
[]
else
range i ((j-i)/step*step + i) []
(* note: the last test checks that no error occurs due to overflows. *)
(*$T
range_by ~step:1 0 0 = [0]
range_by ~step:1 5 0 = []
range_by ~step:2 1 0 = []
range_by ~step:2 0 4 = [0;2;4]
range_by ~step:2 0 5 = [0;2;4]
range_by ~step:~-1 0 0 = [0]
range_by ~step:~-1 0 5 = []
range_by ~step:~-2 0 1 = []
range_by ~step:~-2 5 1 = [5;3;1]
range_by ~step:~-2 5 0 = [5;3;1]
range_by ~step:max_int 0 2 = [0]
*)
(*$Q
Q.(pair small_int small_int) (fun (i,j) -> \
let i = min i j and j = max i j in \
range_by ~step:1 i j = range i j)
*)
let range i j = let range i j =
let rec up i j acc = let rec up i j acc =
if i=j then i::acc else up i (j-1) (j::acc) if i=j then i::acc else up i (j-1) (j::acc)

View file

@ -275,6 +275,13 @@ end
(** {2 Other Constructors} *) (** {2 Other Constructors} *)
val range_by : step:int -> int -> int -> int t
(** [range_by ~step i j] iterates on integers from [i] to [j] included,
where the difference between successive elements is [step].
use a negative [step] for a decreasing list.
@raise Invalid_argument if [step=0]
@since 0.18 *)
val range : int -> int -> int t val range : int -> int -> int t
(** [range i j] iterates on integers from [i] to [j] included . It works (** [range i j] iterates on integers from [i] to [j] included . It works
both for decreasing and increasing ranges *) both for decreasing and increasing ranges *)

View file

@ -93,6 +93,10 @@ let get default x = match x with
| None -> default | None -> default
| Some y -> y | Some y -> y
let get_or ~default x = match x with
| None -> default
| Some y -> y
let get_exn = function let get_exn = function
| Some x -> x | Some x -> x
| None -> invalid_arg "CCOpt.get_exn" | None -> invalid_arg "CCOpt.get_exn"

View file

@ -27,7 +27,7 @@ val compare : ('a -> 'a -> int) -> 'a t -> 'a t -> int
val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool val equal : ('a -> 'a -> bool) -> 'a t -> 'a t -> bool
val return : 'a -> 'a t val return : 'a -> 'a t
(** Monadic return *) (** Monadic return, that is [return x = Some x] *)
val (>|=) : 'a t -> ('a -> 'b) -> 'b t val (>|=) : 'a t -> ('a -> 'b) -> 'b t
(** Infix version of {!map} *) (** Infix version of {!map} *)
@ -62,7 +62,13 @@ val for_all : ('a -> bool) -> 'a t -> bool
val get : 'a -> 'a t -> 'a val get : 'a -> 'a t -> 'a
(** [get default x] unwraps [x], but if [x = None] it returns [default] instead. (** [get default x] unwraps [x], but if [x = None] it returns [default] instead.
@since 0.4.1 *) @since 0.4.1
@deprecated use {!get_or} @since 0.18 *)
val get_or : default:'a -> 'a t -> 'a
(** [get_or ~default o] extracts the value from [o], or
returns [default] if [o = None].
@since 0.18 *)
val get_exn : 'a t -> 'a val get_exn : 'a t -> 'a
(** Open the option, possibly failing if it is [None] (** Open the option, possibly failing if it is [None]
@ -103,6 +109,7 @@ val (<+>) : 'a t -> 'a t -> 'a t
val choice : 'a t list -> 'a t val choice : 'a t list -> 'a t
(** [choice] returns the first non-[None] element of the list, or [None] *) (** [choice] returns the first non-[None] element of the list, or [None] *)
(** {2 Infix Operators} (** {2 Infix Operators}
@since 0.16 *) @since 0.16 *)

View file

@ -639,6 +639,26 @@ let exists2 p s1 s2 =
try iter2 (fun c1 c2 -> if p c1 c2 then raise MyExit) s1 s2; false try iter2 (fun c1 c2 -> if p c1 c2 then raise MyExit) s1 s2; false
with MyExit -> true with MyExit -> true
(** {2 Ascii functions} *)
#if OCAML_MAJOR >= 4 && OCAML_MINOR >= 3
let capitalize_ascii = String.capitalize_ascii
let uncapitalize_ascii = String.uncapitalize_ascii
let uppercase_ascii = String.uppercase_ascii
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
#endif
let pp buf s = let pp buf s =
Buffer.add_char buf '"'; Buffer.add_char buf '"';
Buffer.add_string buf s; Buffer.add_string buf s;

View file

@ -378,6 +378,24 @@ val exists2 : (char -> char -> bool) -> string -> string -> bool
@raise Invalid_argument if the strings have not the same length @raise Invalid_argument if the strings have not the same length
@since 0.12 *) @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 *)
(** {2 Splitting} *) (** {2 Splitting} *)
module Split : sig module Split : sig

View file

@ -243,12 +243,25 @@ let append_list a b = match b with
*) *)
let equal eq v1 v2 = let equal eq v1 v2 =
let n = min v1.size v2.size in v1.size = v2.size
&&
let n = v1.size in
let rec check i = let rec check i =
if i = n i = n || (eq (get v1 i) (get v2 i) && check (i+1))
then v1.size = v2.size in
else eq (get v1 i) (get v2 i) && check (i+1) check 0
in check 0
(*$T
equal (=) (create ()) (create ())
equal (=) (return 42) (return 42)
not (equal (=) (create ()) (return 42))
not (equal (=) (return 42) (create ()))
*)
(*$Q
Q.(let g = list_of_size Gen.(0--10) small_int in pair g g) (fun (l1,l2) -> \
equal (=) (of_list l1) (of_list l2) = (l1=l2))
*)
let compare cmp v1 v2 = let compare cmp v1 v2 =
let n = min v1.size v2.size in let n = min v1.size v2.size in

View file

@ -1,6 +1,6 @@
# OASIS_START # OASIS_START
# DO NOT EDIT (digest: 775c1a5da08322de06b23069a43379ed) # DO NOT EDIT (digest: 048ee564ec86589b85b55f903119ad20)
version = "0.17" version = "0.18"
description = "A modular standard library focused on data structures." description = "A modular standard library focused on data structures."
requires = "bytes result" requires = "bytes result"
archive(byte) = "containers.cma" archive(byte) = "containers.cma"
@ -9,7 +9,7 @@ archive(native) = "containers.cmxa"
archive(native, plugin) = "containers.cmxs" archive(native, plugin) = "containers.cmxs"
exists_if = "containers.cma" exists_if = "containers.cma"
package "unix" ( package "unix" (
version = "0.17" version = "0.18"
description = "A modular standard library focused on data structures." description = "A modular standard library focused on data structures."
requires = "bytes unix" requires = "bytes unix"
archive(byte) = "containers_unix.cma" archive(byte) = "containers_unix.cma"
@ -20,7 +20,7 @@ package "unix" (
) )
package "top" ( package "top" (
version = "0.17" version = "0.18"
description = "A modular standard library focused on data structures." description = "A modular standard library focused on data structures."
requires = requires =
"compiler-libs.common containers containers.data containers.bigarray containers.string containers.unix containers.sexp containers.iter" "compiler-libs.common containers containers.data containers.bigarray containers.string containers.unix containers.sexp containers.iter"
@ -32,7 +32,7 @@ package "top" (
) )
package "thread" ( package "thread" (
version = "0.17" version = "0.18"
description = "A modular standard library focused on data structures." description = "A modular standard library focused on data structures."
requires = "containers threads" requires = "containers threads"
archive(byte) = "containers_thread.cma" archive(byte) = "containers_thread.cma"
@ -43,7 +43,7 @@ package "thread" (
) )
package "string" ( package "string" (
version = "0.17" version = "0.18"
description = "A modular standard library focused on data structures." description = "A modular standard library focused on data structures."
requires = "bytes" requires = "bytes"
archive(byte) = "containers_string.cma" archive(byte) = "containers_string.cma"
@ -54,7 +54,7 @@ package "string" (
) )
package "sexp" ( package "sexp" (
version = "0.17" version = "0.18"
description = "A modular standard library focused on data structures." description = "A modular standard library focused on data structures."
requires = "bytes" requires = "bytes"
archive(byte) = "containers_sexp.cma" archive(byte) = "containers_sexp.cma"
@ -65,7 +65,7 @@ package "sexp" (
) )
package "iter" ( package "iter" (
version = "0.17" version = "0.18"
description = "A modular standard library focused on data structures." description = "A modular standard library focused on data structures."
archive(byte) = "containers_iter.cma" archive(byte) = "containers_iter.cma"
archive(byte, plugin) = "containers_iter.cma" archive(byte, plugin) = "containers_iter.cma"
@ -75,7 +75,7 @@ package "iter" (
) )
package "io" ( package "io" (
version = "0.17" version = "0.18"
description = "A modular standard library focused on data structures." description = "A modular standard library focused on data structures."
requires = "bytes" requires = "bytes"
archive(byte) = "containers_io.cma" archive(byte) = "containers_io.cma"
@ -86,7 +86,7 @@ package "io" (
) )
package "data" ( package "data" (
version = "0.17" version = "0.18"
description = "A modular standard library focused on data structures." description = "A modular standard library focused on data structures."
requires = "bytes" requires = "bytes"
archive(byte) = "containers_data.cma" archive(byte) = "containers_data.cma"
@ -97,7 +97,7 @@ package "data" (
) )
package "bigarray" ( package "bigarray" (
version = "0.17" version = "0.18"
description = "A modular standard library focused on data structures." description = "A modular standard library focused on data structures."
requires = "containers bigarray bytes" requires = "containers bigarray bytes"
archive(byte) = "containers_bigarray.cma" archive(byte) = "containers_bigarray.cma"
@ -108,7 +108,7 @@ package "bigarray" (
) )
package "advanced" ( package "advanced" (
version = "0.17" version = "0.18"
description = "A modular standard library focused on data structures." description = "A modular standard library focused on data structures."
requires = "containers sequence" requires = "containers sequence"
archive(byte) = "containers_advanced.cma" archive(byte) = "containers_advanced.cma"

View file

@ -43,6 +43,10 @@ module Seq = struct
a (fun x -> acc := f !acc x); a (fun x -> acc := f !acc x);
!acc !acc
let to_list seq = fold (fun acc x->x::acc) [] seq |> List.rev let to_list seq = fold (fun acc x->x::acc) [] seq |> List.rev
exception Exit_
let exists_ f seq =
try seq (fun x -> if f x then raise Exit_); false
with Exit_ -> true
end end
(** {2 Interfaces for graphs} *) (** {2 Interfaces for graphs} *)
@ -315,6 +319,15 @@ module Traverse = struct
end end
end end
(** {2 Cycles} *)
let is_dag ?(tbl=mk_table 128) ~graph vs =
Traverse.Event.dfs ~tbl ~graph vs
|> Seq.exists_
(function
| `Edge (_, `Back) -> true
| _ -> false)
(** {2 Topological Sort} *) (** {2 Topological Sort} *)
exception Has_cycle exception Has_cycle

View file

@ -224,6 +224,17 @@ module Traverse : sig
end end
end end
(** {2 Cycles} *)
val is_dag :
?tbl:'v set ->
graph:('v, _) t ->
'v sequence ->
bool
(** [is_dag ~graph vs] returns [true] if the subset of [graph] reachable
from [vs] is acyclic.
@since 0.18 *)
(** {2 Topological Sort} *) (** {2 Topological Sort} *)
exception Has_cycle exception Has_cycle

View file

@ -368,7 +368,7 @@ module Make(W : WORD)
*) *)
(*$Q (*$Q
Q.(pair (list (pair printable_string int)) printable_string) (fun (l,s) -> \ Q.(pair (list (pair (printable_string_of_size Gen.(0 -- 30)) int)) printable_string) (fun (l,s) -> \
let m = String.of_list l in \ let m = String.of_list l in \
let s' = String.longest_prefix s m in \ let s' = String.longest_prefix s m in \
CCString.prefix ~pre:s' s) CCString.prefix ~pre:s' s)

View file

@ -40,6 +40,27 @@ let rec map ~f l =
| lazy (Cons (x,tl)) -> Cons (f x, map ~f tl) | lazy (Cons (x,tl)) -> Cons (f x, map ~f tl)
) )
let filter ~f l =
let rec aux f l = match l with
| lazy Nil -> Nil
| lazy (Cons (x,tl)) when f x -> Cons (x, lazy (aux f tl))
| lazy (Cons (_, tl)) -> aux f tl
in
lazy (aux f l)
(*$=
[2;4;6] (of_list [1;2;3;4;5;6;7] |> filter ~f:(fun x -> x mod 2=0) |> to_list)
[2;4;6] (of_gen Gen.(1 -- max_int) |> filter ~f:(fun x -> x mod 2=0) |> take 3 |> to_list)
*)
let rec take n l =
lazy (
match l with
| _ when n=0 -> Nil
| lazy Nil -> Nil
| lazy (Cons (x,tl)) -> Cons (x, take (n-1) tl)
)
let rec append a b = let rec append a b =
lazy ( lazy (
match a with match a with

View file

@ -31,6 +31,14 @@ val head : 'a t -> ('a * 'a t) option
val map : f:('a -> 'b) -> 'a t -> 'b t val map : f:('a -> 'b) -> 'a t -> 'b t
(** Lazy map *) (** Lazy map *)
val filter : f:('a -> bool) -> 'a t -> 'a t
(** Filter values.
@since 0.18 *)
val take : int -> 'a t -> 'a t
(** Take at most n values.
@since 0.18 *)
val append : 'a t -> 'a t -> 'a t val append : 'a t -> 'a t -> 'a t
(** Lazy concatenation *) (** Lazy concatenation *)