mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-08 12:15:32 -05:00
Merge branch 'master' into stable for 0.18
This commit is contained in:
commit
ed2b741865
27 changed files with 490 additions and 61 deletions
|
|
@ -1,8 +1,19 @@
|
|||
= 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
|
||||
|
||||
=== potentially breaking
|
||||
=== potentially breaking
|
||||
|
||||
- change the semantics of `CCString.find_all` (allow overlaps)
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ can be removed.
|
|||
8. `git merge master`
|
||||
9. `oasis setup; make test doc`
|
||||
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
|
||||
|
||||
|
|
|
|||
10
README.adoc
10
README.adoc
|
|
@ -2,10 +2,11 @@
|
|||
:toc: macro
|
||||
:source-highlighter: pygments
|
||||
|
||||
image::media/logo.png[logo]
|
||||
|
||||
What is _containers_? (take a look at the link:TUTORIAL.adoc[tutorial]!
|
||||
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
|
||||
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::[]
|
||||
|
||||
image::media/logo.png[logo]
|
||||
|
||||
== Change Log
|
||||
|
||||
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/"]
|
||||
|
||||
== Documentation by version
|
||||
|
||||
- http://c-cube.github.io/ocaml-containers/0.17/[0.17]
|
||||
|
|
|
|||
4
_oasis
4
_oasis
|
|
@ -1,6 +1,6 @@
|
|||
OASISFormat: 0.4
|
||||
Name: containers
|
||||
Version: 0.17
|
||||
Version: 0.18
|
||||
Homepage: https://github.com/c-cube/ocaml-containers
|
||||
Authors: Simon Cruanes
|
||||
License: BSD-2-clause
|
||||
|
|
@ -40,7 +40,7 @@ Flag "bigarray"
|
|||
Default: true
|
||||
|
||||
Flag "advanced"
|
||||
Description: Build advanced combinators, including CCLinq (requires "sequence")
|
||||
Description: Build advanced combinators (requires "sequence")
|
||||
Default: true
|
||||
|
||||
Library "containers"
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ by ocamlfind).
|
|||
|
||||
{4 Core Modules (extension of the standard library)}
|
||||
|
||||
{b findlib name}: containers
|
||||
|
||||
{!modules:
|
||||
CCArray
|
||||
CCBool
|
||||
|
|
@ -63,6 +65,8 @@ such as:
|
|||
|
||||
{4 Containers.data}
|
||||
|
||||
{b findlib name}: containers.data
|
||||
|
||||
Various data structures.
|
||||
|
||||
{!modules:
|
||||
|
|
@ -123,6 +127,8 @@ CCLazy_list}
|
|||
|
||||
{4 String}
|
||||
|
||||
{b findlib name}: containers.string
|
||||
|
||||
{!modules:
|
||||
CCApp_parse
|
||||
CCKMP
|
||||
|
|
@ -139,6 +145,8 @@ Use bigarrays to hold large strings and map files directly into memory.
|
|||
|
||||
{4 Advanced}
|
||||
|
||||
{b findlib name}: containers.advanced
|
||||
|
||||
This module is qualified with [Containers_advanced]. It
|
||||
requires {{:https://github.com/c-cube/sequence} Sequence}.
|
||||
|
||||
|
|
@ -152,7 +160,11 @@ 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:
|
||||
CCBlockingQueue
|
||||
|
|
|
|||
174
myocamlbuild.ml
174
myocamlbuild.ml
|
|
@ -1,5 +1,5 @@
|
|||
(* OASIS_START *)
|
||||
(* DO NOT EDIT (digest: b119194f5742ac2f3cdceac9a223dda7) *)
|
||||
(* DO NOT EDIT (digest: 9ba607f1a3e839f1c1e8ea449ddfab16) *)
|
||||
module OASISGettext = struct
|
||||
(* # 22 "src/oasis/OASISGettext.ml" *)
|
||||
|
||||
|
|
@ -29,6 +29,166 @@ module OASISGettext = struct
|
|||
|
||||
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
|
||||
(* # 22 "src/oasis/OASISExpr.ml" *)
|
||||
|
||||
|
|
@ -129,7 +289,7 @@ module OASISExpr = struct
|
|||
end
|
||||
|
||||
|
||||
# 132 "myocamlbuild.ml"
|
||||
# 292 "myocamlbuild.ml"
|
||||
module BaseEnvLight = struct
|
||||
(* # 22 "src/base/BaseEnvLight.ml" *)
|
||||
|
||||
|
|
@ -234,7 +394,7 @@ module BaseEnvLight = struct
|
|||
end
|
||||
|
||||
|
||||
# 237 "myocamlbuild.ml"
|
||||
# 397 "myocamlbuild.ml"
|
||||
module MyOCamlbuildFindlib = struct
|
||||
(* # 22 "src/plugins/ocamlbuild/MyOCamlbuildFindlib.ml" *)
|
||||
|
||||
|
|
@ -516,7 +676,7 @@ module MyOCamlbuildBase = struct
|
|||
| nm, [], intf_modules ->
|
||||
ocaml_lib nm;
|
||||
let cmis =
|
||||
List.map (fun m -> (String.uncapitalize m) ^ ".cmi")
|
||||
List.map (fun m -> (OASISString.uncapitalize_ascii m) ^ ".cmi")
|
||||
intf_modules in
|
||||
dep ["ocaml"; "link"; "library"; "file:"^nm^".cma"] cmis
|
||||
| nm, dir :: tl, intf_modules ->
|
||||
|
|
@ -529,7 +689,7 @@ module MyOCamlbuildBase = struct
|
|||
["compile"; "infer_interface"; "doc"])
|
||||
tl;
|
||||
let cmis =
|
||||
List.map (fun m -> dir^"/"^(String.uncapitalize m)^".cmi")
|
||||
List.map (fun m -> dir^"/"^(OASISString.uncapitalize_ascii m)^".cmi")
|
||||
intf_modules in
|
||||
dep ["ocaml"; "link"; "library"; "file:"^dir^"/"^nm^".cma"]
|
||||
cmis)
|
||||
|
|
@ -603,7 +763,7 @@ module MyOCamlbuildBase = struct
|
|||
end
|
||||
|
||||
|
||||
# 606 "myocamlbuild.ml"
|
||||
# 766 "myocamlbuild.ml"
|
||||
open Ocamlbuild_plugin;;
|
||||
let package_default =
|
||||
{
|
||||
|
|
@ -669,7 +829,7 @@ let conf = {MyOCamlbuildFindlib.no_automatic_syntax = false}
|
|||
|
||||
let dispatch_default = MyOCamlbuildBase.dispatch_default conf package_default;;
|
||||
|
||||
# 673 "myocamlbuild.ml"
|
||||
# 833 "myocamlbuild.ml"
|
||||
(* OASIS_STOP *)
|
||||
let doc_intro = "doc/intro.txt" ;;
|
||||
|
||||
|
|
|
|||
1
opam
1
opam
|
|
@ -26,6 +26,7 @@ remove: [
|
|||
]
|
||||
depends: [
|
||||
"ocamlfind" {build}
|
||||
"oasis" {build}
|
||||
"base-bytes"
|
||||
"result"
|
||||
"cppo" {build}
|
||||
|
|
|
|||
76
setup.ml
76
setup.ml
|
|
@ -1,9 +1,9 @@
|
|||
(* setup.ml generated for the first time by OASIS v0.4.4 *)
|
||||
|
||||
(* 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
|
||||
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;
|
||||
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
|
||||
|
||||
|
|
@ -315,19 +342,15 @@ module OASISUtils = struct
|
|||
|
||||
|
||||
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 =
|
||||
Hashtbl.Make
|
||||
(struct
|
||||
type t = string
|
||||
|
||||
let equal s1 s2 =
|
||||
(String.lowercase s1) = (String.lowercase s2)
|
||||
|
||||
let hash s =
|
||||
Hashtbl.hash (String.lowercase s)
|
||||
let equal s1 s2 = (compare_csl s1 s2) = 0
|
||||
let hash s = Hashtbl.hash (OASISString.lowercase_ascii s)
|
||||
end)
|
||||
|
||||
module SetStringCsl =
|
||||
|
|
@ -365,7 +388,7 @@ module OASISUtils = struct
|
|||
else
|
||||
buf
|
||||
in
|
||||
String.lowercase buf
|
||||
OASISString.lowercase_ascii buf
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -471,7 +494,7 @@ module PropList = struct
|
|||
order = Queue.create ();
|
||||
name_norm =
|
||||
(if case_insensitive then
|
||||
String.lowercase
|
||||
OASISString.lowercase_ascii
|
||||
else
|
||||
fun s -> s);
|
||||
}
|
||||
|
|
@ -1822,13 +1845,13 @@ module OASISUnixPath = struct
|
|||
let capitalize_file f =
|
||||
let dir = dirname f in
|
||||
let base = basename f in
|
||||
concat dir (String.capitalize base)
|
||||
concat dir (OASISString.capitalize_ascii base)
|
||||
|
||||
|
||||
let uncapitalize_file f =
|
||||
let dir = dirname f in
|
||||
let base = basename f in
|
||||
concat dir (String.uncapitalize base)
|
||||
concat dir (OASISString.uncapitalize_ascii base)
|
||||
|
||||
|
||||
end
|
||||
|
|
@ -2890,7 +2913,7 @@ module OASISFileUtil = struct
|
|||
end
|
||||
|
||||
|
||||
# 2893 "setup.ml"
|
||||
# 2916 "setup.ml"
|
||||
module BaseEnvLight = struct
|
||||
(* # 22 "src/base/BaseEnvLight.ml" *)
|
||||
|
||||
|
|
@ -2995,7 +3018,7 @@ module BaseEnvLight = struct
|
|||
end
|
||||
|
||||
|
||||
# 2998 "setup.ml"
|
||||
# 3021 "setup.ml"
|
||||
module BaseContext = struct
|
||||
(* # 22 "src/base/BaseContext.ml" *)
|
||||
|
||||
|
|
@ -5406,7 +5429,7 @@ module BaseSetup = struct
|
|||
end
|
||||
|
||||
|
||||
# 5409 "setup.ml"
|
||||
# 5432 "setup.ml"
|
||||
module InternalConfigurePlugin = struct
|
||||
(* # 22 "src/plugins/internal/InternalConfigurePlugin.ml" *)
|
||||
|
||||
|
|
@ -5845,8 +5868,8 @@ module InternalInstallPlugin = struct
|
|||
let make_fnames modul sufx =
|
||||
List.fold_right
|
||||
begin fun sufx accu ->
|
||||
(String.capitalize modul ^ sufx) ::
|
||||
(String.uncapitalize modul ^ sufx) ::
|
||||
(OASISString.capitalize_ascii modul ^ sufx) ::
|
||||
(OASISString.uncapitalize_ascii modul ^ sufx) ::
|
||||
accu
|
||||
end
|
||||
sufx
|
||||
|
|
@ -6270,7 +6293,7 @@ module InternalInstallPlugin = struct
|
|||
end
|
||||
|
||||
|
||||
# 6273 "setup.ml"
|
||||
# 6296 "setup.ml"
|
||||
module OCamlbuildCommon = struct
|
||||
(* # 22 "src/plugins/ocamlbuild/OCamlbuildCommon.ml" *)
|
||||
|
||||
|
|
@ -6648,7 +6671,7 @@ module OCamlbuildDocPlugin = struct
|
|||
end
|
||||
|
||||
|
||||
# 6651 "setup.ml"
|
||||
# 6674 "setup.ml"
|
||||
module CustomPlugin = struct
|
||||
(* # 22 "src/plugins/custom/CustomPlugin.ml" *)
|
||||
|
||||
|
|
@ -6796,7 +6819,7 @@ module CustomPlugin = struct
|
|||
end
|
||||
|
||||
|
||||
# 6799 "setup.ml"
|
||||
# 6822 "setup.ml"
|
||||
open OASISTypes;;
|
||||
|
||||
let setup_t =
|
||||
|
|
@ -6875,7 +6898,7 @@ let setup_t =
|
|||
alpha_features = ["ocamlbuild_more_args"];
|
||||
beta_features = [];
|
||||
name = "containers";
|
||||
version = "0.17";
|
||||
version = "0.18";
|
||||
license =
|
||||
OASISLicense.DEP5License
|
||||
(OASISLicense.DEP5Unit
|
||||
|
|
@ -6987,7 +7010,7 @@ let setup_t =
|
|||
{
|
||||
flag_description =
|
||||
Some
|
||||
"Build advanced combinators, including CCLinq (requires \"sequence\")";
|
||||
"Build advanced combinators (requires \"sequence\")";
|
||||
flag_default = [(OASISExpr.EBool true, true)]
|
||||
});
|
||||
Library
|
||||
|
|
@ -7721,8 +7744,9 @@ let setup_t =
|
|||
plugin_data = []
|
||||
};
|
||||
oasis_fn = Some "_oasis";
|
||||
oasis_version = "0.4.5";
|
||||
oasis_digest = Some "\168\138o\130\169\030i2!\170\1730n\148\174\208";
|
||||
oasis_version = "0.4.6";
|
||||
oasis_digest =
|
||||
Some "\006\139\194\135\189\021\197\018\208\031.\187\212'\016\192";
|
||||
oasis_exec = None;
|
||||
oasis_setup_args = [];
|
||||
setup_update = false
|
||||
|
|
@ -7730,6 +7754,6 @@ let setup_t =
|
|||
|
||||
let setup () = BaseSetup.setup setup_t;;
|
||||
|
||||
# 7734 "setup.ml"
|
||||
# 7758 "setup.ml"
|
||||
(* OASIS_STOP *)
|
||||
let () = setup ();;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
the order of execution.
|
||||
|
||||
@deprecated use {{: https://github.com/c-cube/olinq} OLinq} (once released)
|
||||
@deprecated use {{: https://github.com/c-cube/olinq} OLinq}
|
||||
|
||||
{[
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ module type S = sig
|
|||
|
||||
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 length : _ t -> int
|
||||
|
|
@ -291,6 +295,21 @@ let length = Array.length
|
|||
|
||||
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 fold = Array.fold_left
|
||||
|
|
@ -568,6 +587,24 @@ module Sub = struct
|
|||
if i<0 || j>=a.j then invalid_arg "Array.Sub.get";
|
||||
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 j = a.i + i in
|
||||
if i<0 || j>=a.j then invalid_arg "Array.Sub.set";
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@ module type S = sig
|
|||
|
||||
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 length : _ t -> int
|
||||
|
|
|
|||
|
|
@ -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 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
|
||||
@since 0.17 *)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,16 @@ let (@@) f x = f x
|
|||
|
||||
#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_binop f g x y = g (f x) (f y)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
@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}
|
||||
|
||||
Functions with a fixed domain are monads in their codomain *)
|
||||
|
|
|
|||
|
|
@ -792,6 +792,38 @@ module Idx = struct
|
|||
*)
|
||||
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 rec up i j acc =
|
||||
if i=j then i::acc else up i (j-1) (j::acc)
|
||||
|
|
|
|||
|
|
@ -275,6 +275,13 @@ end
|
|||
|
||||
(** {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
|
||||
(** [range i j] iterates on integers from [i] to [j] included . It works
|
||||
both for decreasing and increasing ranges *)
|
||||
|
|
|
|||
|
|
@ -93,6 +93,10 @@ let get default x = match x with
|
|||
| None -> default
|
||||
| Some y -> y
|
||||
|
||||
let get_or ~default x = match x with
|
||||
| None -> default
|
||||
| Some y -> y
|
||||
|
||||
let get_exn = function
|
||||
| Some x -> x
|
||||
| None -> invalid_arg "CCOpt.get_exn"
|
||||
|
|
|
|||
|
|
@ -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 return : 'a -> 'a t
|
||||
(** Monadic return *)
|
||||
(** Monadic return, that is [return x = Some x] *)
|
||||
|
||||
val (>|=) : 'a t -> ('a -> 'b) -> 'b t
|
||||
(** Infix version of {!map} *)
|
||||
|
|
@ -62,7 +62,13 @@ val for_all : ('a -> bool) -> 'a t -> bool
|
|||
|
||||
val get : 'a -> 'a t -> 'a
|
||||
(** [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
|
||||
(** 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
|
||||
(** [choice] returns the first non-[None] element of the list, or [None] *)
|
||||
|
||||
(** {2 Infix Operators}
|
||||
@since 0.16 *)
|
||||
|
||||
|
|
|
|||
|
|
@ -639,6 +639,26 @@ let exists2 p s1 s2 =
|
|||
try iter2 (fun c1 c2 -> if p c1 c2 then raise MyExit) s1 s2; false
|
||||
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 =
|
||||
Buffer.add_char buf '"';
|
||||
Buffer.add_string buf s;
|
||||
|
|
|
|||
|
|
@ -378,6 +378,24 @@ val exists2 : (char -> char -> bool) -> string -> string -> bool
|
|||
@raise Invalid_argument if the strings have not the same length
|
||||
@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} *)
|
||||
|
||||
module Split : sig
|
||||
|
|
|
|||
|
|
@ -243,12 +243,25 @@ let append_list a b = match b with
|
|||
*)
|
||||
|
||||
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 =
|
||||
if i = n
|
||||
then v1.size = v2.size
|
||||
else eq (get v1 i) (get v2 i) && check (i+1)
|
||||
in check 0
|
||||
i = n || (eq (get v1 i) (get v2 i) && check (i+1))
|
||||
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 n = min v1.size v2.size in
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# OASIS_START
|
||||
# DO NOT EDIT (digest: 775c1a5da08322de06b23069a43379ed)
|
||||
version = "0.17"
|
||||
# DO NOT EDIT (digest: 048ee564ec86589b85b55f903119ad20)
|
||||
version = "0.18"
|
||||
description = "A modular standard library focused on data structures."
|
||||
requires = "bytes result"
|
||||
archive(byte) = "containers.cma"
|
||||
|
|
@ -9,7 +9,7 @@ archive(native) = "containers.cmxa"
|
|||
archive(native, plugin) = "containers.cmxs"
|
||||
exists_if = "containers.cma"
|
||||
package "unix" (
|
||||
version = "0.17"
|
||||
version = "0.18"
|
||||
description = "A modular standard library focused on data structures."
|
||||
requires = "bytes unix"
|
||||
archive(byte) = "containers_unix.cma"
|
||||
|
|
@ -20,7 +20,7 @@ package "unix" (
|
|||
)
|
||||
|
||||
package "top" (
|
||||
version = "0.17"
|
||||
version = "0.18"
|
||||
description = "A modular standard library focused on data structures."
|
||||
requires =
|
||||
"compiler-libs.common containers containers.data containers.bigarray containers.string containers.unix containers.sexp containers.iter"
|
||||
|
|
@ -32,7 +32,7 @@ package "top" (
|
|||
)
|
||||
|
||||
package "thread" (
|
||||
version = "0.17"
|
||||
version = "0.18"
|
||||
description = "A modular standard library focused on data structures."
|
||||
requires = "containers threads"
|
||||
archive(byte) = "containers_thread.cma"
|
||||
|
|
@ -43,7 +43,7 @@ package "thread" (
|
|||
)
|
||||
|
||||
package "string" (
|
||||
version = "0.17"
|
||||
version = "0.18"
|
||||
description = "A modular standard library focused on data structures."
|
||||
requires = "bytes"
|
||||
archive(byte) = "containers_string.cma"
|
||||
|
|
@ -54,7 +54,7 @@ package "string" (
|
|||
)
|
||||
|
||||
package "sexp" (
|
||||
version = "0.17"
|
||||
version = "0.18"
|
||||
description = "A modular standard library focused on data structures."
|
||||
requires = "bytes"
|
||||
archive(byte) = "containers_sexp.cma"
|
||||
|
|
@ -65,7 +65,7 @@ package "sexp" (
|
|||
)
|
||||
|
||||
package "iter" (
|
||||
version = "0.17"
|
||||
version = "0.18"
|
||||
description = "A modular standard library focused on data structures."
|
||||
archive(byte) = "containers_iter.cma"
|
||||
archive(byte, plugin) = "containers_iter.cma"
|
||||
|
|
@ -75,7 +75,7 @@ package "iter" (
|
|||
)
|
||||
|
||||
package "io" (
|
||||
version = "0.17"
|
||||
version = "0.18"
|
||||
description = "A modular standard library focused on data structures."
|
||||
requires = "bytes"
|
||||
archive(byte) = "containers_io.cma"
|
||||
|
|
@ -86,7 +86,7 @@ package "io" (
|
|||
)
|
||||
|
||||
package "data" (
|
||||
version = "0.17"
|
||||
version = "0.18"
|
||||
description = "A modular standard library focused on data structures."
|
||||
requires = "bytes"
|
||||
archive(byte) = "containers_data.cma"
|
||||
|
|
@ -97,7 +97,7 @@ package "data" (
|
|||
)
|
||||
|
||||
package "bigarray" (
|
||||
version = "0.17"
|
||||
version = "0.18"
|
||||
description = "A modular standard library focused on data structures."
|
||||
requires = "containers bigarray bytes"
|
||||
archive(byte) = "containers_bigarray.cma"
|
||||
|
|
@ -108,7 +108,7 @@ package "bigarray" (
|
|||
)
|
||||
|
||||
package "advanced" (
|
||||
version = "0.17"
|
||||
version = "0.18"
|
||||
description = "A modular standard library focused on data structures."
|
||||
requires = "containers sequence"
|
||||
archive(byte) = "containers_advanced.cma"
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ module Seq = struct
|
|||
a (fun x -> acc := f !acc x);
|
||||
!acc
|
||||
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
|
||||
|
||||
(** {2 Interfaces for graphs} *)
|
||||
|
|
@ -315,6 +319,15 @@ module Traverse = struct
|
|||
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} *)
|
||||
|
||||
exception Has_cycle
|
||||
|
|
|
|||
|
|
@ -224,6 +224,17 @@ module Traverse : sig
|
|||
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} *)
|
||||
|
||||
exception Has_cycle
|
||||
|
|
|
|||
|
|
@ -368,7 +368,7 @@ module Make(W : WORD)
|
|||
*)
|
||||
|
||||
(*$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 s' = String.longest_prefix s m in \
|
||||
CCString.prefix ~pre:s' s)
|
||||
|
|
|
|||
|
|
@ -40,6 +40,27 @@ let rec map ~f l =
|
|||
| 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 =
|
||||
lazy (
|
||||
match a with
|
||||
|
|
|
|||
|
|
@ -31,6 +31,14 @@ val head : 'a t -> ('a * 'a t) option
|
|||
val map : f:('a -> 'b) -> 'a t -> 'b t
|
||||
(** 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
|
||||
(** Lazy concatenation *)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue