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,5 +1,16 @@
= 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

View file

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

View file

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

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

View file

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

View file

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

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

View file

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

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
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_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";

View file

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

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

View file

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

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

View file

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

View file

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

View file

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

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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