From a5ed794b4c8290a5d1567a9f861f7c69dc5d12fa Mon Sep 17 00:00:00 2001 From: John Whitington Date: Fri, 31 Jul 2020 14:24:50 +0100 Subject: [PATCH] Check-typo and indenting all done --- stdlib/hashtbl.mli | 23 +- stdlib/map.mli | 24 +- stdlib/moreLabels.mli | 2103 +++++++++++----------- stdlib/set.mli | 12 +- stdlib/templates/hashtbl.template.mli | 23 +- stdlib/templates/map.template.mli | 24 +- stdlib/templates/moreLabels.template.mli | 16 +- stdlib/templates/set.template.mli | 12 +- tools/unlabel | 20 +- 9 files changed, 1148 insertions(+), 1109 deletions(-) diff --git a/stdlib/hashtbl.mli b/stdlib/hashtbl.mli index e6f08bace..00df561be 100644 --- a/stdlib/hashtbl.mli +++ b/stdlib/hashtbl.mli @@ -50,13 +50,13 @@ val create : ?random: (* thwart tools/unlabel *) bool -> int -> ('a, 'b) t A hash table that is created with [random] set to [true] uses the seeded hash function {!seeded_hash} with a seed that is randomly chosen at hash - table creation time. In effect, the hash function used is randomly selected - among [2^{30}] different hash functions. All these hash functions have - different collision patterns, rendering ineffective the denial-of-service - attack described above. However, because of randomization, enumerating all - elements of the hash table using {!fold} or {!iter} is no longer - deterministic: elements are enumerated in different orders at different runs - of the program. + table creation time. In effect, the hash function used is randomly + selected among [2^{30}] different hash functions. All these hash + functions have different collision patterns, rendering ineffective the + denial-of-service attack described above. However, because of + randomization, enumerating all elements of the hash table using {!fold} + or {!iter} is no longer deterministic: elements are enumerated in + different orders at different runs of the program. If no [random] parameter is given, hash tables are created in non-random mode by default. This default can be changed @@ -136,7 +136,8 @@ val iter : ('a -> 'b -> unit) -> ('a, 'b) t -> unit by [f] during the iteration. *) -val filter_map_inplace: ('a -> 'b -> 'b option) -> ('a, 'b) t -> unit +val filter_map_inplace: ('a -> 'b -> 'b option) -> ('a, 'b) t -> + unit (** [Hashtbl.filter_map_inplace f tbl] applies [f] to all bindings in table [tbl] and update each binding depending on the result of [f]. If [f] returns [None], the binding is discarded. If it @@ -346,7 +347,8 @@ module type S = val replace : 'a t -> key -> 'a -> unit val mem : 'a t -> key -> bool val iter : (key -> 'a -> unit) -> 'a t -> unit - val filter_map_inplace: (key -> 'a -> 'a option) -> 'a t -> unit + val filter_map_inplace: (key -> 'a -> 'a option) -> 'a t -> + unit (** @since 4.03.0 *) val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b @@ -420,7 +422,8 @@ module type SeededS = val replace : 'a t -> key -> 'a -> unit val mem : 'a t -> key -> bool val iter : (key -> 'a -> unit) -> 'a t -> unit - val filter_map_inplace: (key -> 'a -> 'a option) -> 'a t -> unit + val filter_map_inplace: (key -> 'a -> 'a option) -> 'a t -> + unit (** @since 4.03.0 *) val fold : (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b diff --git a/stdlib/map.mli b/stdlib/map.mli index db3547d0d..1c2752868 100644 --- a/stdlib/map.mli +++ b/stdlib/map.mli @@ -103,8 +103,8 @@ module type S = *) val singleton: key -> 'a -> 'a t - (** [singleton x y] returns the one-element map that contains a binding [y] - for [x]. + (** [singleton x y] returns the one-element map that contains a binding + [y] for [x]. @since 3.12.0 *) @@ -116,7 +116,8 @@ module type S = @before 4.03 Physical equality was not ensured. *) val merge: - (key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t + (key -> 'a option -> 'b option -> 'c option) -> + 'a t -> 'b t -> 'c t (** [merge f m1 m2] computes a map whose keys are a subset of the keys of [m1] and of [m2]. The presence of each such binding, and the corresponding value, is determined with the function [f]. @@ -291,16 +292,16 @@ module type S = For example, [find_first (fun k -> Ord.compare k x >= 0) m] will return the first binding [k, v] of [m] where [Ord.compare k x >= 0] - (intuitively: [k >= x]), or raise [Not_found] if [x] is greater than any - element of [m]. + (intuitively: [k >= x]), or raise [Not_found] if [x] is greater than + any element of [m]. @since 4.05 *) val find_first_opt: (key -> bool) -> 'a t -> (key * 'a) option - (** [find_first_opt f m], where [f] is a monotonically increasing function, - returns an option containing the binding of [m] with the lowest key [k] - such that [f k], or [None] if no such key exists. + (** [find_first_opt f m], where [f] is a monotonically increasing + function, returns an option containing the binding of [m] with the + lowest key [k] such that [f k], or [None] if no such key exists. @since 4.05 *) @@ -312,9 +313,10 @@ module type S = *) val find_last_opt: (key -> bool) -> 'a t -> (key * 'a) option - (** [find_last_opt f m], where [f] is a monotonically decreasing function, - returns an option containing the binding of [m] with the highest key [k] - such that [f k], or [None] if no such key exists. + (** [find_last_opt f m], where [f] is a monotonically decreasing + function, returns an option containing the binding of [m] with + the highest key [k] such that [f k], or [None] if no such key + exists. @since 4.05 *) diff --git a/stdlib/moreLabels.mli b/stdlib/moreLabels.mli index a8ade6e8e..b20750fb5 100644 --- a/stdlib/moreLabels.mli +++ b/stdlib/moreLabels.mli @@ -18,1151 +18,1162 @@ (** Extra labeled libraries. - This meta-module provides labelized version of the {!Hashtbl}, - {!Map} and {!Set} modules. + This meta-module provides labelized versions of the {!Hashtbl}, {!Map} and + {!Set} modules. - They only differ by their labels. They are provided to help - porting from previous versions of OCaml. - The contents of this module are subject to change. + This module is intended to be used through [open MoreLabels] which replaces + {!Hashtbl}, {!Map}, and {!Set} with their labeled counterparts. + + For example: + {[ + open MoreLabels + + Hashtbl.iter ~f:(fun ~key ~data -> g key data) table + ]} *) module Hashtbl : sig -(** Hash tables and hash functions. - - Hash tables are hashed association tables, with in-place modification. -*) - - -(** {1 Generic interface} *) - - -type (!'a, !'b) t = ('a, 'b) Hashtbl.t -(** The type of hash tables from type ['a] to type ['b]. *) - -val create : ?random: (* thwart tools/unlabel *) bool -> int -> ('a, 'b) t -(** [Hashtbl.create n] creates a new, empty hash table, with - initial size [n]. For best results, [n] should be on the - order of the expected number of elements that will be in - the table. The table grows as needed, so [n] is just an - initial guess. - - The optional [~random] parameter (a boolean) controls whether - the internal organization of the hash table is randomized at each - execution of [Hashtbl.create] or deterministic over all executions. - - A hash table that is created with [~random] set to [false] uses a - fixed hash function ({!hash}) to distribute keys among - buckets. As a consequence, collisions between keys happen - deterministically. In Web-facing applications or other - security-sensitive applications, the deterministic collision - patterns can be exploited by a malicious user to create a - denial-of-service attack: the attacker sends input crafted to - create many collisions in the table, slowing the application down. - - A hash table that is created with [~random] set to [true] uses the seeded - hash function {!seeded_hash} with a seed that is randomly chosen at hash - table creation time. In effect, the hash function used is randomly selected - among [2^{30}] different hash functions. All these hash functions have - different collision patterns, rendering ineffective the denial-of-service - attack described above. However, because of randomization, enumerating all - elements of the hash table using {!fold} or {!iter} is no longer - deterministic: elements are enumerated in different orders at different runs - of the program. - - If no [~random] parameter is given, hash tables are created - in non-random mode by default. This default can be changed - either programmatically by calling {!randomize} or by - setting the [R] flag in the [OCAMLRUNPARAM] environment variable. - - @before 4.00.0 the [random] parameter was not present and all - hash tables were created in non-randomized mode. *) - -val clear : ('a, 'b) t -> unit -(** Empty a hash table. Use [reset] instead of [clear] to shrink the - size of the bucket table to its initial size. *) - -val reset : ('a, 'b) t -> unit -(** Empty a hash table and shrink the size of the bucket table - to its initial size. - @since 4.00.0 *) - -val copy : ('a, 'b) t -> ('a, 'b) t -(** Return a copy of the given hashtable. *) - -val add : ('a, 'b) t -> key:'a -> data:'b -> unit -(** [Hashtbl.add tbl ~key ~data] adds a binding of [key] to [data] - in table [tbl]. - Previous bindings for [key] are not removed, but simply - hidden. That is, after performing {!remove}[ tbl key], - the previous binding for [key], if any, is restored. - (Same behavior as with association lists.) *) - -val find : ('a, 'b) t -> 'a -> 'b -(** [Hashtbl.find tbl x] returns the current binding of [x] in [tbl], - or raises [Not_found] if no such binding exists. *) - -val find_opt : ('a, 'b) t -> 'a -> 'b option -(** [Hashtbl.find_opt tbl x] returns the current binding of [x] in [tbl], - or [None] if no such binding exists. - @since 4.05 *) - -val find_all : ('a, 'b) t -> 'a -> 'b list -(** [Hashtbl.find_all tbl x] returns the list of all data - associated with [x] in [tbl]. - The current binding is returned first, then the previous - bindings, in reverse order of introduction in the table. *) - -val mem : ('a, 'b) t -> 'a -> bool -(** [Hashtbl.mem tbl x] checks if [x] is bound in [tbl]. *) - -val remove : ('a, 'b) t -> 'a -> unit -(** [Hashtbl.remove tbl x] removes the current binding of [x] in [tbl], - restoring the previous binding if it exists. - It does nothing if [x] is not bound in [tbl]. *) - -val replace : ('a, 'b) t -> key:'a -> data:'b -> unit -(** [Hashtbl.replace tbl ~key ~data] replaces the current binding of [key] - in [tbl] by a binding of [key] to [data]. If [key] is unbound in [tbl], - a binding of [key] to [data] is added to [tbl]. - This is functionally equivalent to {!remove}[ tbl key] - followed by {!add}[ tbl key data]. *) - -val iter : f:(key:'a -> data:'b -> unit) -> ('a, 'b) t -> unit -(** [Hashtbl.iter ~f tbl] applies [f] to all bindings in table [tbl]. - [f] receives the key as first argument, and the associated value - as second argument. Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - - If the hash table was created in non-randomized mode, the order - in which the bindings are enumerated is reproducible between - successive runs of the program, and even between minor versions - of OCaml. For randomized hash tables, the order of enumeration - is entirely random. - - The behavior is not defined if the hash table is modified - by [f] during the iteration. -*) - -val filter_map_inplace: f:(key:'a -> data:'b -> 'b option) -> ('a, 'b) t -> unit -(** [Hashtbl.filter_map_inplace ~f tbl] applies [f] to all bindings in - table [tbl] and update each binding depending on the result of - [f]. If [f] returns [None], the binding is discarded. If it - returns [Some new_val], the binding is update to associate the key - to [new_val]. - - Other comments for {!iter} apply as well. - @since 4.03.0 *) - -val fold : f:(key:'a -> data:'b -> 'c -> 'c) -> ('a, 'b) t -> init:'c -> 'c -(** [Hashtbl.fold ~f tbl ~init] computes - [(f kN dN ... (f k1 d1 init)...)], - where [k1 ... kN] are the keys of all bindings in [tbl], - and [d1 ... dN] are the associated values. - Each binding is presented exactly once to [f]. - - The order in which the bindings are passed to [f] is unspecified. - However, if the table contains several bindings for the same key, - they are passed to [f] in reverse order of introduction, that is, - the most recent binding is passed first. - - If the hash table was created in non-randomized mode, the order - in which the bindings are enumerated is reproducible between - successive runs of the program, and even between minor versions - of OCaml. For randomized hash tables, the order of enumeration - is entirely random. - - The behavior is not defined if the hash table is modified - by [f] during the iteration. -*) - -val length : ('a, 'b) t -> int -(** [Hashtbl.length tbl] returns the number of bindings in [tbl]. - It takes constant time. Multiple bindings are counted once each, so - [Hashtbl.length] gives the number of times [Hashtbl.iter] calls its - first argument. *) - -val randomize : unit -> unit -(** After a call to [Hashtbl.randomize()], hash tables are created in - randomized mode by default: {!create} returns randomized - hash tables, unless the [~random:false] optional parameter is given. - The same effect can be achieved by setting the [R] parameter in - the [OCAMLRUNPARAM] environment variable. - - It is recommended that applications or Web frameworks that need to - protect themselves against the denial-of-service attack described - in {!create} call [Hashtbl.randomize()] at initialization - time. - - Note that once [Hashtbl.randomize()] was called, there is no way - to revert to the non-randomized default behavior of {!create}. - This is intentional. Non-randomized hash tables can still be - created using [Hashtbl.create ~random:false]. - - @since 4.00.0 *) - -val is_randomized : unit -> bool -(** Return [true] if the tables are currently created in randomized mode - by default, [false] otherwise. - @since 4.03.0 *) - -val rebuild : ?random (* thwart tools/unlabel *) :bool -> - ('a, 'b) t -> ('a, 'b) t -(** Return a copy of the given hashtable. Unlike {!copy}, - [{!rebuild} h] re-hashes all the (key, value) entries of - the original table [h]. The returned hash table is randomized if - [h] was randomized, or the optional [random] parameter is true, or - if the default is to create randomized hash tables; see - {!create} for more information. - - {!rebuild} can safely be used to import a hash table built - by an old version of the {!Hashtbl} module, then marshaled to - persistent storage. After unmarshaling, apply {!rebuild} - to produce a hash table for the current version of the {!Hashtbl} - module. - - @since 4.12.0 *) - -(** @since 4.00.0 *) -type statistics = Hashtbl.statistics = { - num_bindings: int; - (** Number of bindings present in the table. - Same value as returned by {!length}. *) - num_buckets: int; - (** Number of buckets in the table. *) - max_bucket_length: int; - (** Maximal number of bindings per bucket. *) - bucket_histogram: int array - (** Histogram of bucket sizes. This array [histo] has - length [max_bucket_length + 1]. The value of - [histo.(i)] is the number of buckets whose size is [i]. *) -} - -val stats : ('a, 'b) t -> statistics -(** [Hashtbl.stats tbl] returns statistics about the table [tbl]: - number of buckets, size of the biggest bucket, distribution of - buckets by size. - @since 4.00.0 *) - -(** {1 Iterators} *) - -val to_seq : ('a,'b) t -> ('a * 'b) Seq.t -(** Iterate on the whole table. The order in which the bindings - appear in the sequence is unspecified. However, if the table contains - several bindings for the same key, they appear in reversed order of - introduction, that is, the most recent binding appears first. - - The behavior is not defined if the hash table is modified - during the iteration. - - @since 4.07 *) - -val to_seq_keys : ('a,_) t -> 'a Seq.t -(** Same as [Seq.map fst (to_seq m)] - @since 4.07 *) - -val to_seq_values : (_,'b) t -> 'b Seq.t -(** Same as [Seq.map snd (to_seq m)] - @since 4.07 *) - -val add_seq : ('a,'b) t -> ('a * 'b) Seq.t -> unit -(** Add the given bindings to the table, using {!add} - @since 4.07 *) - -val replace_seq : ('a,'b) t -> ('a * 'b) Seq.t -> unit -(** Add the given bindings to the table, using {!replace} - @since 4.07 *) - -val of_seq : ('a * 'b) Seq.t -> ('a, 'b) t -(** Build a table from the given bindings. The bindings are added - in the same order they appear in the sequence, using {!replace_seq}, - which means that if two pairs have the same key, only the latest one - will appear in the table. - @since 4.07 *) - -(** {1 Functorial interface} *) - -(** The functorial interface allows the use of specific comparison - and hash functions, either for performance/security concerns, - or because keys are not hashable/comparable with the polymorphic builtins. - - For instance, one might want to specialize a table for integer keys: - {[ - module IntHash = - struct - type t = int - let equal i j = i=j - let hash i = i land max_int - end - - module IntHashtbl = Hashtbl.Make(IntHash) - - let h = IntHashtbl.create 17 in - IntHashtbl.add h 12 "hello" - ]} - - This creates a new module [IntHashtbl], with a new type ['a - IntHashtbl.t] of tables from [int] to ['a]. In this example, [h] - contains [string] values so its type is [string IntHashtbl.t]. - - Note that the new type ['a IntHashtbl.t] is not compatible with - the type [('a,'b) Hashtbl.t] of the generic interface. For - example, [Hashtbl.length h] would not type-check, you must use - [IntHashtbl.length]. -*) - -module type HashedType = - sig - type t - (** The type of the hashtable keys. *) - - val equal : t -> t -> bool - (** The equality predicate used to compare keys. *) - - val hash : t -> int - (** A hashing function on keys. It must be such that if two keys are - equal according to [equal], then they have identical hash values - as computed by [hash]. - Examples: suitable ([equal], [hash]) pairs for arbitrary key - types include -- ([(=)], {!hash}) for comparing objects by structure - (provided objects do not contain floats) -- ([(fun x y -> compare x y = 0)], {!hash}) - for comparing objects by structure - and handling {!Stdlib.nan} correctly -- ([(==)], {!hash}) for comparing objects by physical - equality (e.g. for mutable or cyclic objects). *) - end -(** The input signature of the functor {!Make}. *) - -module type S = - sig - type key - type !'a t - val create : int -> 'a t - val clear : 'a t -> unit - val reset : 'a t -> unit (** @since 4.00.0 *) - - val copy : 'a t -> 'a t - val add : 'a t -> key:key -> data:'a -> unit - val remove : 'a t -> key -> unit - val find : 'a t -> key -> 'a - val find_opt : 'a t -> key -> 'a option - (** @since 4.05.0 *) - - val find_all : 'a t -> key -> 'a list - val replace : 'a t -> key:key -> data:'a -> unit - val mem : 'a t -> key -> bool - val iter : f:(key:key -> data:'a -> unit) -> 'a t -> unit - val filter_map_inplace: f:(key:key -> data:'a -> 'a option) -> 'a t -> unit - (** @since 4.03.0 *) - - val fold : f:(key:key -> data:'a -> 'b -> 'b) -> 'a t -> init:'b -> 'b - val length : 'a t -> int - val stats: 'a t -> statistics (** @since 4.00.0 *) - - val to_seq : 'a t -> (key * 'a) Seq.t - (** @since 4.07 *) - - val to_seq_keys : _ t -> key Seq.t - (** @since 4.07 *) - - val to_seq_values : 'a t -> 'a Seq.t - (** @since 4.07 *) - - val add_seq : 'a t -> (key * 'a) Seq.t -> unit - (** @since 4.07 *) - - val replace_seq : 'a t -> (key * 'a) Seq.t -> unit - (** @since 4.07 *) - - val of_seq : (key * 'a) Seq.t -> 'a t - (** @since 4.07 *) - end -(** The output signature of the functor {!Make}. *) - - module Make : functor (H : HashedType) -> S - with type key = H.t - and type 'a t = 'a Hashtbl.Make(H).t -(** Functor building an implementation of the hashtable structure. - The functor [Hashtbl.Make] returns a structure containing - a type [key] of keys and a type ['a t] of hash tables - associating data of type ['a] to keys of type [key]. - The operations perform similarly to those of the generic - interface, but use the hashing and equality functions - specified in the functor argument [H] instead of generic - equality and hashing. Since the hash function is not seeded, - the [create] operation of the result structure always returns - non-randomized hash tables. *) - -module type SeededHashedType = - sig - type t - (** The type of the hashtable keys. *) - - val equal: t -> t -> bool - (** The equality predicate used to compare keys. *) - - val hash: int -> t -> int - (** A seeded hashing function on keys. The first argument is - the seed. It must be the case that if [equal x y] is true, - then [hash seed x = hash seed y] for any value of [seed]. - A suitable choice for [hash] is the function {!seeded_hash} - below. *) - end -(** The input signature of the functor {!MakeSeeded}. - @since 4.00.0 *) - -module type SeededS = - sig - type key - type !'a t - val create : ?random (* thwart tools/unlabel *) :bool -> int -> 'a t - val clear : 'a t -> unit - val reset : 'a t -> unit - val copy : 'a t -> 'a t - val add : 'a t -> key:key -> data:'a -> unit - val remove : 'a t -> key -> unit - val find : 'a t -> key -> 'a - val find_opt : 'a t -> key -> 'a option (** @since 4.05.0 *) - - val find_all : 'a t -> key -> 'a list - val replace : 'a t -> key:key -> data:'a -> unit - val mem : 'a t -> key -> bool - val iter : f:(key:key -> data:'a -> unit) -> 'a t -> unit - val filter_map_inplace: f:(key:key -> data:'a -> 'a option) -> 'a t -> unit - (** @since 4.03.0 *) - - val fold : f:(key:key -> data:'a -> 'b -> 'b) -> 'a t -> init:'b -> 'b - val length : 'a t -> int - val stats: 'a t -> statistics - - val to_seq : 'a t -> (key * 'a) Seq.t - (** @since 4.07 *) - - val to_seq_keys : _ t -> key Seq.t - (** @since 4.07 *) - - val to_seq_values : 'a t -> 'a Seq.t - (** @since 4.07 *) - - val add_seq : 'a t -> (key * 'a) Seq.t -> unit - (** @since 4.07 *) - - val replace_seq : 'a t -> (key * 'a) Seq.t -> unit - (** @since 4.07 *) - - val of_seq : (key * 'a) Seq.t -> 'a t - (** @since 4.07 *) - end -(** The output signature of the functor {!MakeSeeded}. - @since 4.00.0 *) - - module MakeSeeded (H : SeededHashedType) : SeededS + (** Hash tables and hash functions. + + Hash tables are hashed association tables, with in-place modification. + *) + + + (** {1 Generic interface} *) + + + type (!'a, !'b) t = ('a, 'b) Hashtbl.t + (** The type of hash tables from type ['a] to type ['b]. *) + + val create : ?random: (* thwart tools/unlabel *) bool -> int -> ('a, 'b) t + (** [Hashtbl.create n] creates a new, empty hash table, with + initial size [n]. For best results, [n] should be on the + order of the expected number of elements that will be in + the table. The table grows as needed, so [n] is just an + initial guess. + + The optional [~random] parameter (a boolean) controls whether + the internal organization of the hash table is randomized at each + execution of [Hashtbl.create] or deterministic over all executions. + + A hash table that is created with [~random] set to [false] uses a + fixed hash function ({!hash}) to distribute keys among + buckets. As a consequence, collisions between keys happen + deterministically. In Web-facing applications or other + security-sensitive applications, the deterministic collision + patterns can be exploited by a malicious user to create a + denial-of-service attack: the attacker sends input crafted to + create many collisions in the table, slowing the application down. + + A hash table that is created with [~random] set to [true] uses the seeded + hash function {!seeded_hash} with a seed that is randomly chosen at hash + table creation time. In effect, the hash function used is randomly + selected among [2^{30}] different hash functions. All these hash + functions have different collision patterns, rendering ineffective the + denial-of-service attack described above. However, because of + randomization, enumerating all elements of the hash table using {!fold} + or {!iter} is no longer deterministic: elements are enumerated in + different orders at different runs of the program. + + If no [~random] parameter is given, hash tables are created + in non-random mode by default. This default can be changed + either programmatically by calling {!randomize} or by + setting the [R] flag in the [OCAMLRUNPARAM] environment variable. + + @before 4.00.0 the [random] parameter was not present and all + hash tables were created in non-randomized mode. *) + + val clear : ('a, 'b) t -> unit + (** Empty a hash table. Use [reset] instead of [clear] to shrink the + size of the bucket table to its initial size. *) + + val reset : ('a, 'b) t -> unit + (** Empty a hash table and shrink the size of the bucket table + to its initial size. + @since 4.00.0 *) + + val copy : ('a, 'b) t -> ('a, 'b) t + (** Return a copy of the given hashtable. *) + + val add : ('a, 'b) t -> key:'a -> data:'b -> unit + (** [Hashtbl.add tbl ~key ~data] adds a binding of [key] to [data] + in table [tbl]. + Previous bindings for [key] are not removed, but simply + hidden. That is, after performing {!remove}[ tbl key], + the previous binding for [key], if any, is restored. + (Same behavior as with association lists.) *) + + val find : ('a, 'b) t -> 'a -> 'b + (** [Hashtbl.find tbl x] returns the current binding of [x] in [tbl], + or raises [Not_found] if no such binding exists. *) + + val find_opt : ('a, 'b) t -> 'a -> 'b option + (** [Hashtbl.find_opt tbl x] returns the current binding of [x] in [tbl], + or [None] if no such binding exists. + @since 4.05 *) + + val find_all : ('a, 'b) t -> 'a -> 'b list + (** [Hashtbl.find_all tbl x] returns the list of all data + associated with [x] in [tbl]. + The current binding is returned first, then the previous + bindings, in reverse order of introduction in the table. *) + + val mem : ('a, 'b) t -> 'a -> bool + (** [Hashtbl.mem tbl x] checks if [x] is bound in [tbl]. *) + + val remove : ('a, 'b) t -> 'a -> unit + (** [Hashtbl.remove tbl x] removes the current binding of [x] in [tbl], + restoring the previous binding if it exists. + It does nothing if [x] is not bound in [tbl]. *) + + val replace : ('a, 'b) t -> key:'a -> data:'b -> unit + (** [Hashtbl.replace tbl ~key ~data] replaces the current binding of [key] + in [tbl] by a binding of [key] to [data]. If [key] is unbound in [tbl], + a binding of [key] to [data] is added to [tbl]. + This is functionally equivalent to {!remove}[ tbl key] + followed by {!add}[ tbl key data]. *) + + val iter : f:(key:'a -> data:'b -> unit) -> ('a, 'b) t -> unit + (** [Hashtbl.iter ~f tbl] applies [f] to all bindings in table [tbl]. + [f] receives the key as first argument, and the associated value + as second argument. Each binding is presented exactly once to [f]. + + The order in which the bindings are passed to [f] is unspecified. + However, if the table contains several bindings for the same key, + they are passed to [f] in reverse order of introduction, that is, + the most recent binding is passed first. + + If the hash table was created in non-randomized mode, the order + in which the bindings are enumerated is reproducible between + successive runs of the program, and even between minor versions + of OCaml. For randomized hash tables, the order of enumeration + is entirely random. + + The behavior is not defined if the hash table is modified + by [f] during the iteration. + *) + + val filter_map_inplace: f:(key:'a -> data:'b -> 'b option) -> ('a, 'b) t -> + unit + (** [Hashtbl.filter_map_inplace ~f tbl] applies [f] to all bindings in + table [tbl] and update each binding depending on the result of + [f]. If [f] returns [None], the binding is discarded. If it + returns [Some new_val], the binding is update to associate the key + to [new_val]. + + Other comments for {!iter} apply as well. + @since 4.03.0 *) + + val fold : f:(key:'a -> data:'b -> 'c -> 'c) -> ('a, 'b) t -> init:'c -> 'c + (** [Hashtbl.fold ~f tbl ~init] computes + [(f kN dN ... (f k1 d1 init)...)], + where [k1 ... kN] are the keys of all bindings in [tbl], + and [d1 ... dN] are the associated values. + Each binding is presented exactly once to [f]. + + The order in which the bindings are passed to [f] is unspecified. + However, if the table contains several bindings for the same key, + they are passed to [f] in reverse order of introduction, that is, + the most recent binding is passed first. + + If the hash table was created in non-randomized mode, the order + in which the bindings are enumerated is reproducible between + successive runs of the program, and even between minor versions + of OCaml. For randomized hash tables, the order of enumeration + is entirely random. + + The behavior is not defined if the hash table is modified + by [f] during the iteration. + *) + + val length : ('a, 'b) t -> int + (** [Hashtbl.length tbl] returns the number of bindings in [tbl]. + It takes constant time. Multiple bindings are counted once each, so + [Hashtbl.length] gives the number of times [Hashtbl.iter] calls its + first argument. *) + + val randomize : unit -> unit + (** After a call to [Hashtbl.randomize()], hash tables are created in + randomized mode by default: {!create} returns randomized + hash tables, unless the [~random:false] optional parameter is given. + The same effect can be achieved by setting the [R] parameter in + the [OCAMLRUNPARAM] environment variable. + + It is recommended that applications or Web frameworks that need to + protect themselves against the denial-of-service attack described + in {!create} call [Hashtbl.randomize()] at initialization + time. + + Note that once [Hashtbl.randomize()] was called, there is no way + to revert to the non-randomized default behavior of {!create}. + This is intentional. Non-randomized hash tables can still be + created using [Hashtbl.create ~random:false]. + + @since 4.00.0 *) + + val is_randomized : unit -> bool + (** Return [true] if the tables are currently created in randomized mode + by default, [false] otherwise. + @since 4.03.0 *) + + val rebuild : ?random (* thwart tools/unlabel *) :bool -> + ('a, 'b) t -> ('a, 'b) t + (** Return a copy of the given hashtable. Unlike {!copy}, + [{!rebuild} h] re-hashes all the (key, value) entries of + the original table [h]. The returned hash table is randomized if + [h] was randomized, or the optional [random] parameter is true, or + if the default is to create randomized hash tables; see + {!create} for more information. + + {!rebuild} can safely be used to import a hash table built + by an old version of the {!Hashtbl} module, then marshaled to + persistent storage. After unmarshaling, apply {!rebuild} + to produce a hash table for the current version of the {!Hashtbl} + module. + + @since 4.12.0 *) + + (** @since 4.00.0 *) + type statistics = Hashtbl.statistics = { + num_bindings: int; + (** Number of bindings present in the table. + Same value as returned by {!length}. *) + num_buckets: int; + (** Number of buckets in the table. *) + max_bucket_length: int; + (** Maximal number of bindings per bucket. *) + bucket_histogram: int array + (** Histogram of bucket sizes. This array [histo] has + length [max_bucket_length + 1]. The value of + [histo.(i)] is the number of buckets whose size is [i]. *) + } + + val stats : ('a, 'b) t -> statistics + (** [Hashtbl.stats tbl] returns statistics about the table [tbl]: + number of buckets, size of the biggest bucket, distribution of + buckets by size. + @since 4.00.0 *) + + (** {1 Iterators} *) + + val to_seq : ('a,'b) t -> ('a * 'b) Seq.t + (** Iterate on the whole table. The order in which the bindings + appear in the sequence is unspecified. However, if the table contains + several bindings for the same key, they appear in reversed order of + introduction, that is, the most recent binding appears first. + + The behavior is not defined if the hash table is modified + during the iteration. + + @since 4.07 *) + + val to_seq_keys : ('a,_) t -> 'a Seq.t + (** Same as [Seq.map fst (to_seq m)] + @since 4.07 *) + + val to_seq_values : (_,'b) t -> 'b Seq.t + (** Same as [Seq.map snd (to_seq m)] + @since 4.07 *) + + val add_seq : ('a,'b) t -> ('a * 'b) Seq.t -> unit + (** Add the given bindings to the table, using {!add} + @since 4.07 *) + + val replace_seq : ('a,'b) t -> ('a * 'b) Seq.t -> unit + (** Add the given bindings to the table, using {!replace} + @since 4.07 *) + + val of_seq : ('a * 'b) Seq.t -> ('a, 'b) t + (** Build a table from the given bindings. The bindings are added + in the same order they appear in the sequence, using {!replace_seq}, + which means that if two pairs have the same key, only the latest one + will appear in the table. + @since 4.07 *) + + (** {1 Functorial interface} *) + + (** The functorial interface allows the use of specific comparison + and hash functions, either for performance/security concerns, + or because keys are not hashable/comparable with the polymorphic builtins. + + For instance, one might want to specialize a table for integer keys: + {[ + module IntHash = + struct + type t = int + let equal i j = i=j + let hash i = i land max_int + end + + module IntHashtbl = Hashtbl.Make(IntHash) + + let h = IntHashtbl.create 17 in + IntHashtbl.add h 12 "hello" + ]} + + This creates a new module [IntHashtbl], with a new type ['a + IntHashtbl.t] of tables from [int] to ['a]. In this example, [h] + contains [string] values so its type is [string IntHashtbl.t]. + + Note that the new type ['a IntHashtbl.t] is not compatible with + the type [('a,'b) Hashtbl.t] of the generic interface. For + example, [Hashtbl.length h] would not type-check, you must use + [IntHashtbl.length]. + *) + + module type HashedType = + sig + type t + (** The type of the hashtable keys. *) + + val equal : t -> t -> bool + (** The equality predicate used to compare keys. *) + + val hash : t -> int + (** A hashing function on keys. It must be such that if two keys are + equal according to [equal], then they have identical hash values + as computed by [hash]. + Examples: suitable ([equal], [hash]) pairs for arbitrary key + types include + - ([(=)], {!hash}) for comparing objects by structure + (provided objects do not contain floats) + - ([(fun x y -> compare x y = 0)], {!hash}) + for comparing objects by structure + and handling {!Stdlib.nan} correctly + - ([(==)], {!hash}) for comparing objects by physical + equality (e.g. for mutable or cyclic objects). *) + end + (** The input signature of the functor {!Make}. *) + + module type S = + sig + type key + type !'a t + val create : int -> 'a t + val clear : 'a t -> unit + val reset : 'a t -> unit (** @since 4.00.0 *) + + val copy : 'a t -> 'a t + val add : 'a t -> key:key -> data:'a -> unit + val remove : 'a t -> key -> unit + val find : 'a t -> key -> 'a + val find_opt : 'a t -> key -> 'a option + (** @since 4.05.0 *) + + val find_all : 'a t -> key -> 'a list + val replace : 'a t -> key:key -> data:'a -> unit + val mem : 'a t -> key -> bool + val iter : f:(key:key -> data:'a -> unit) -> 'a t -> unit + val filter_map_inplace: f:(key:key -> data:'a -> 'a option) -> 'a t -> + unit + (** @since 4.03.0 *) + + val fold : f:(key:key -> data:'a -> 'b -> 'b) -> 'a t -> init:'b -> 'b + val length : 'a t -> int + val stats: 'a t -> statistics (** @since 4.00.0 *) + + val to_seq : 'a t -> (key * 'a) Seq.t + (** @since 4.07 *) + + val to_seq_keys : _ t -> key Seq.t + (** @since 4.07 *) + + val to_seq_values : 'a t -> 'a Seq.t + (** @since 4.07 *) + + val add_seq : 'a t -> (key * 'a) Seq.t -> unit + (** @since 4.07 *) + + val replace_seq : 'a t -> (key * 'a) Seq.t -> unit + (** @since 4.07 *) + + val of_seq : (key * 'a) Seq.t -> 'a t + (** @since 4.07 *) + end + (** The output signature of the functor {!Make}. *) + + module Make : functor (H : HashedType) -> S + with type key = H.t + and type 'a t = 'a Hashtbl.Make(H).t + (** Functor building an implementation of the hashtable structure. + The functor [Hashtbl.Make] returns a structure containing + a type [key] of keys and a type ['a t] of hash tables + associating data of type ['a] to keys of type [key]. + The operations perform similarly to those of the generic + interface, but use the hashing and equality functions + specified in the functor argument [H] instead of generic + equality and hashing. Since the hash function is not seeded, + the [create] operation of the result structure always returns + non-randomized hash tables. *) + + module type SeededHashedType = + sig + type t + (** The type of the hashtable keys. *) + + val equal: t -> t -> bool + (** The equality predicate used to compare keys. *) + + val hash: int -> t -> int + (** A seeded hashing function on keys. The first argument is + the seed. It must be the case that if [equal x y] is true, + then [hash seed x = hash seed y] for any value of [seed]. + A suitable choice for [hash] is the function {!seeded_hash} + below. *) + end + (** The input signature of the functor {!MakeSeeded}. + @since 4.00.0 *) + + module type SeededS = + sig + type key + type !'a t + val create : ?random (* thwart tools/unlabel *) :bool -> int -> 'a t + val clear : 'a t -> unit + val reset : 'a t -> unit + val copy : 'a t -> 'a t + val add : 'a t -> key:key -> data:'a -> unit + val remove : 'a t -> key -> unit + val find : 'a t -> key -> 'a + val find_opt : 'a t -> key -> 'a option (** @since 4.05.0 *) + + val find_all : 'a t -> key -> 'a list + val replace : 'a t -> key:key -> data:'a -> unit + val mem : 'a t -> key -> bool + val iter : f:(key:key -> data:'a -> unit) -> 'a t -> unit + val filter_map_inplace: f:(key:key -> data:'a -> 'a option) -> 'a t -> + unit + (** @since 4.03.0 *) + + val fold : f:(key:key -> data:'a -> 'b -> 'b) -> 'a t -> init:'b -> 'b + val length : 'a t -> int + val stats: 'a t -> statistics + + val to_seq : 'a t -> (key * 'a) Seq.t + (** @since 4.07 *) + + val to_seq_keys : _ t -> key Seq.t + (** @since 4.07 *) + + val to_seq_values : 'a t -> 'a Seq.t + (** @since 4.07 *) + + val add_seq : 'a t -> (key * 'a) Seq.t -> unit + (** @since 4.07 *) + + val replace_seq : 'a t -> (key * 'a) Seq.t -> unit + (** @since 4.07 *) + + val of_seq : (key * 'a) Seq.t -> 'a t + (** @since 4.07 *) + end + (** The output signature of the functor {!MakeSeeded}. + @since 4.00.0 *) + + module MakeSeeded (H : SeededHashedType) : SeededS with type key = H.t and type 'a t = 'a Hashtbl.MakeSeeded(H).t -(** Functor building an implementation of the hashtable structure. - The functor [Hashtbl.MakeSeeded] returns a structure containing - a type [key] of keys and a type ['a t] of hash tables - associating data of type ['a] to keys of type [key]. - The operations perform similarly to those of the generic - interface, but use the seeded hashing and equality functions - specified in the functor argument [H] instead of generic - equality and hashing. The [create] operation of the - result structure supports the [~random] optional parameter - and returns randomized hash tables if [~random:true] is passed - or if randomization is globally on (see {!Hashtbl.randomize}). - @since 4.00.0 *) + (** Functor building an implementation of the hashtable structure. + The functor [Hashtbl.MakeSeeded] returns a structure containing + a type [key] of keys and a type ['a t] of hash tables + associating data of type ['a] to keys of type [key]. + The operations perform similarly to those of the generic + interface, but use the seeded hashing and equality functions + specified in the functor argument [H] instead of generic + equality and hashing. The [create] operation of the + result structure supports the [~random] optional parameter + and returns randomized hash tables if [~random:true] is passed + or if randomization is globally on (see {!Hashtbl.randomize}). + @since 4.00.0 *) -(** {1 The polymorphic hash functions} *) + (** {1 The polymorphic hash functions} *) -val hash : 'a -> int -(** [Hashtbl.hash x] associates a nonnegative integer to any value of - any type. It is guaranteed that - if [x = y] or [Stdlib.compare x y = 0], then [hash x = hash y]. - Moreover, [hash] always terminates, even on cyclic structures. *) + val hash : 'a -> int + (** [Hashtbl.hash x] associates a nonnegative integer to any value of + any type. It is guaranteed that + if [x = y] or [Stdlib.compare x y = 0], then [hash x = hash y]. + Moreover, [hash] always terminates, even on cyclic structures. *) -val seeded_hash : int -> 'a -> int -(** A variant of {!hash} that is further parameterized by - an integer seed. - @since 4.00.0 *) + val seeded_hash : int -> 'a -> int + (** A variant of {!hash} that is further parameterized by + an integer seed. + @since 4.00.0 *) -val hash_param : int -> int -> 'a -> int -(** [Hashtbl.hash_param meaningful total x] computes a hash value for [x], - with the same properties as for [hash]. The two extra integer - parameters [meaningful] and [total] give more precise control over - hashing. Hashing performs a breadth-first, left-to-right traversal - of the structure [x], stopping after [meaningful] meaningful nodes - were encountered, or [total] nodes (meaningful or not) were - encountered. If [total] as specified by the user exceeds a certain - value, currently 256, then it is capped to that value. - Meaningful nodes are: integers; floating-point - numbers; strings; characters; booleans; and constant - constructors. Larger values of [meaningful] and [total] means that - more nodes are taken into account to compute the final hash value, - and therefore collisions are less likely to happen. However, - hashing takes longer. The parameters [meaningful] and [total] - govern the tradeoff between accuracy and speed. As default - choices, {!hash} and {!seeded_hash} take - [meaningful = 10] and [total = 100]. *) + val hash_param : int -> int -> 'a -> int + (** [Hashtbl.hash_param meaningful total x] computes a hash value for [x], + with the same properties as for [hash]. The two extra integer + parameters [meaningful] and [total] give more precise control over + hashing. Hashing performs a breadth-first, left-to-right traversal + of the structure [x], stopping after [meaningful] meaningful nodes + were encountered, or [total] nodes (meaningful or not) were + encountered. If [total] as specified by the user exceeds a certain + value, currently 256, then it is capped to that value. + Meaningful nodes are: integers; floating-point + numbers; strings; characters; booleans; and constant + constructors. Larger values of [meaningful] and [total] means that + more nodes are taken into account to compute the final hash value, + and therefore collisions are less likely to happen. However, + hashing takes longer. The parameters [meaningful] and [total] + govern the tradeoff between accuracy and speed. As default + choices, {!hash} and {!seeded_hash} take + [meaningful = 10] and [total = 100]. *) -val seeded_hash_param : int -> int -> int -> 'a -> int -(** A variant of {!hash_param} that is further parameterized by - an integer seed. Usage: - [Hashtbl.seeded_hash_param meaningful total seed x]. - @since 4.00.0 *) + val seeded_hash_param : int -> int -> int -> 'a -> int + (** A variant of {!hash_param} that is further parameterized by + an integer seed. Usage: + [Hashtbl.seeded_hash_param meaningful total seed x]. + @since 4.00.0 *) end module Map : sig -(** Association tables over ordered types. + (** Association tables over ordered types. - This module implements applicative association tables, also known as - finite maps or dictionaries, given a total ordering function - over the keys. - All operations over maps are purely applicative (no side-effects). - The implementation uses balanced binary trees, and therefore searching - and insertion take time logarithmic in the size of the map. + This module implements applicative association tables, also known as + finite maps or dictionaries, given a total ordering function + over the keys. + All operations over maps are purely applicative (no side-effects). + The implementation uses balanced binary trees, and therefore searching + and insertion take time logarithmic in the size of the map. - For instance: - {[ - module IntPairs = - struct - type t = int * int - let compare (x0,y0) (x1,y1) = - match Stdlib.compare x0 x1 with - 0 -> Stdlib.compare y0 y1 - | c -> c - end + For instance: + {[ + module IntPairs = + struct + type t = int * int + let compare (x0,y0) (x1,y1) = + match Stdlib.compare x0 x1 with + 0 -> Stdlib.compare y0 y1 + | c -> c + end - module PairsMap = Map.Make(IntPairs) + module PairsMap = Map.Make(IntPairs) - let m = PairsMap.(empty |> add (0,1) "hello" |> add (1,0) "world") - ]} + let m = PairsMap.(empty |> add (0,1) "hello" |> add (1,0) "world") + ]} - This creates a new module [PairsMap], with a new type ['a PairsMap.t] - of maps from [int * int] to ['a]. In this example, [m] contains [string] - values so its type is [string PairsMap.t]. -*) + This creates a new module [PairsMap], with a new type ['a PairsMap.t] + of maps from [int * int] to ['a]. In this example, [m] contains [string] + values so its type is [string PairsMap.t]. + *) -module type OrderedType = - sig - type t + module type OrderedType = + sig + type t + (** The type of the map keys. *) + + val compare : t -> t -> int + (** A total ordering function over the keys. + This is a two-argument function [f] such that + [f e1 e2] is zero if the keys [e1] and [e2] are equal, + [f e1 e2] is strictly negative if [e1] is smaller than [e2], + and [f e1 e2] is strictly positive if [e1] is greater than [e2]. + Example: a suitable ordering function is the generic structural + comparison function {!Stdlib.compare}. *) + end + (** Input signature of the functor {!Make}. *) + + module type S = + sig + type key (** The type of the map keys. *) - val compare : t -> t -> int - (** A total ordering function over the keys. - This is a two-argument function [f] such that - [f e1 e2] is zero if the keys [e1] and [e2] are equal, - [f e1 e2] is strictly negative if [e1] is smaller than [e2], - and [f e1 e2] is strictly positive if [e1] is greater than [e2]. - Example: a suitable ordering function is the generic structural - comparison function {!Stdlib.compare}. *) - end -(** Input signature of the functor {!Make}. *) + type !+'a t + (** The type of maps from type [key] to type ['a]. *) -module type S = - sig - type key - (** The type of the map keys. *) + val empty: 'a t + (** The empty map. *) - type !+'a t - (** The type of maps from type [key] to type ['a]. *) + val is_empty: 'a t -> bool + (** Test whether a map is empty or not. *) - val empty: 'a t - (** The empty map. *) + val mem: key -> 'a t -> bool + (** [mem x m] returns [true] if [m] contains a binding for [x], + and [false] otherwise. *) - val is_empty: 'a t -> bool - (** Test whether a map is empty or not. *) + val add: key:key -> data:'a -> 'a t -> 'a t + (** [add ~key ~data m] returns a map containing the same bindings as + [m], plus a binding of [key] to [data]. If [key] was already bound + in [m] to a value that is physically equal to [data], + [m] is returned unchanged (the result of the function is + then physically equal to [m]). Otherwise, the previous binding + of [key] in [m] disappears. + @before 4.03 Physical equality was not ensured. *) - val mem: key -> 'a t -> bool - (** [mem x m] returns [true] if [m] contains a binding for [x], - and [false] otherwise. *) + val update: key:key -> f:('a option -> 'a option) -> 'a t -> 'a t + (** [update ~key ~f m] returns a map containing the same bindings as + [m], except for the binding of [key]. Depending on the value of + [y] where [y] is [f (find_opt key m)], the binding of [key] is + added, removed or updated. If [y] is [None], the binding is + removed if it exists; otherwise, if [y] is [Some z] then [key] + is associated to [z] in the resulting map. If [key] was already + bound in [m] to a value that is physically equal to [z], [m] + is returned unchanged (the result of the function is then + physically equal to [m]). + @since 4.06.0 + *) - val add: key:key -> data:'a -> 'a t -> 'a t - (** [add ~key ~data m] returns a map containing the same bindings as - [m], plus a binding of [key] to [data]. If [key] was already bound - in [m] to a value that is physically equal to [data], - [m] is returned unchanged (the result of the function is - then physically equal to [m]). Otherwise, the previous binding - of [key] in [m] disappears. - @before 4.03 Physical equality was not ensured. *) - - val update: key:key -> f:('a option -> 'a option) -> 'a t -> 'a t - (** [update ~key ~f m] returns a map containing the same bindings as - [m], except for the binding of [key]. Depending on the value of - [y] where [y] is [f (find_opt key m)], the binding of [key] is - added, removed or updated. If [y] is [None], the binding is - removed if it exists; otherwise, if [y] is [Some z] then [key] - is associated to [z] in the resulting map. If [key] was already - bound in [m] to a value that is physically equal to [z], [m] - is returned unchanged (the result of the function is then - physically equal to [m]). - @since 4.06.0 - *) - - val singleton: key -> 'a -> 'a t - (** [singleton x y] returns the one-element map that contains a binding [y] - for [x]. - @since 3.12.0 - *) - - val remove: key -> 'a t -> 'a t - (** [remove x m] returns a map containing the same bindings as - [m], except for [x] which is unbound in the returned map. - If [x] was not in [m], [m] is returned unchanged - (the result of the function is then physically equal to [m]). - @before 4.03 Physical equality was not ensured. *) - - val merge: - f:(key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t - (** [merge ~f m1 m2] computes a map whose keys are a subset of the keys of - [m1] and of [m2]. The presence of each such binding, and the - corresponding value, is determined with the function [f]. - In terms of the [find_opt] operation, we have - [find_opt x (merge f m1 m2) = f x (find_opt x m1) (find_opt x m2)] - for any key [x], provided that [f x None None = None]. - @since 3.12.0 - *) - - val union: f:(key -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t - (** [union ~f m1 m2] computes a map whose keys are a subset of the keys - of [m1] and of [m2]. When the same binding is defined in both - arguments, the function [f] is used to combine them. - This is a special case of [merge]: [union f m1 m2] is equivalent - to [merge f' m1 m2], where - - [f' _key None None = None] - - [f' _key (Some v) None = Some v] - - [f' _key None (Some v) = Some v] - - [f' key (Some v1) (Some v2) = f key v1 v2] - - @since 4.03.0 - *) - - val compare: cmp:('a -> 'a -> int) -> 'a t -> 'a t -> int - (** Total ordering between maps. The first argument is a total ordering - used to compare data associated with equal keys in the two maps. *) - - val equal: cmp:('a -> 'a -> bool) -> 'a t -> 'a t -> bool - (** [equal ~cmp m1 m2] tests whether the maps [m1] and [m2] are - equal, that is, contain equal keys and associate them with - equal data. [cmp] is the equality predicate used to compare - the data associated with the keys. *) - - val iter: f:(key:key -> data:'a -> unit) -> 'a t -> unit - (** [iter ~f m] applies [f] to all bindings in map [m]. - [f] receives the key as first argument, and the associated value - as second argument. The bindings are passed to [f] in increasing - order with respect to the ordering over the type of the keys. *) - - val fold: f:(key:key -> data:'a -> 'b -> 'b) -> 'a t -> init:'b -> 'b - (** [fold ~f m ~init] computes [(f kN dN ... (f k1 d1 init)...)], - where [k1 ... kN] are the keys of all bindings in [m] - (in increasing order), and [d1 ... dN] are the associated data. *) - - val for_all: f:(key -> 'a -> bool) -> 'a t -> bool - (** [for_all ~f m] checks if all the bindings of the map - satisfy the predicate [f]. - @since 3.12.0 - *) - - val exists: f:(key -> 'a -> bool) -> 'a t -> bool - (** [exists ~f m] checks if at least one binding of the map - satisfies the predicate [f]. - @since 3.12.0 - *) - - val filter: f:(key -> 'a -> bool) -> 'a t -> 'a t - (** [filter ~f m] returns the map with all the bindings in [m] - that satisfy predicate [p]. If every binding in [m] satisfies [f], - [m] is returned unchanged (the result of the function is then - physically equal to [m]) - @since 3.12.0 - @before 4.03 Physical equality was not ensured. - *) - - val filter_map: f:(key -> 'a -> 'b option) -> 'a t -> 'b t - (** [filter_map ~f m] applies the function [f] to every binding of - [m], and builds a map from the results. For each binding - [(k, v)] in the input map: - - if [f k v] is [None] then [k] is not in the result, - - if [f k v] is [Some v'] then the binding [(k, v')] - is in the output map. - - For example, the following function on maps whose values are lists - {[ - filter_map - (fun _k li -> match li with [] -> None | _::tl -> Some tl) - m - ]} - drops all bindings of [m] whose value is an empty list, and pops - the first element of each value that is non-empty. - - @since 4.11.0 - *) - - val partition: f:(key -> 'a -> bool) -> 'a t -> 'a t * 'a t - (** [partition ~f m] returns a pair of maps [(m1, m2)], where - [m1] contains all the bindings of [m] that satisfy the - predicate [f], and [m2] is the map with all the bindings of - [m] that do not satisfy [f]. - @since 3.12.0 - *) - - val cardinal: 'a t -> int - (** Return the number of bindings of a map. - @since 3.12.0 - *) - - val bindings: 'a t -> (key * 'a) list - (** Return the list of all bindings of the given map. - The returned list is sorted in increasing order of keys with respect - to the ordering [Ord.compare], where [Ord] is the argument - given to {!Make}. - @since 3.12.0 - *) - - val min_binding: 'a t -> (key * 'a) - (** Return the binding with the smallest key in a given map - (with respect to the [Ord.compare] ordering), or raise - [Not_found] if the map is empty. - @since 3.12.0 - *) - - val min_binding_opt: 'a t -> (key * 'a) option - (** Return the binding with the smallest key in the given map - (with respect to the [Ord.compare] ordering), or [None] - if the map is empty. - @since 4.05 - *) - - val max_binding: 'a t -> (key * 'a) - (** Same as {!S.min_binding}, but returns the binding with - the largest key in the given map. - @since 3.12.0 - *) - - val max_binding_opt: 'a t -> (key * 'a) option - (** Same as {!S.min_binding_opt}, but returns the binding with - the largest key in the given map. - @since 4.05 - *) - - val choose: 'a t -> (key * 'a) - (** Return one binding of the given map, or raise [Not_found] if - the map is empty. Which binding is chosen is unspecified, - but equal bindings will be chosen for equal maps. - @since 3.12.0 - *) - - val choose_opt: 'a t -> (key * 'a) option - (** Return one binding of the given map, or [None] if - the map is empty. Which binding is chosen is unspecified, - but equal bindings will be chosen for equal maps. - @since 4.05 - *) - - val split: key -> 'a t -> 'a t * 'a option * 'a t - (** [split x m] returns a triple [(l, data, r)], where - [l] is the map with all the bindings of [m] whose key - is strictly less than [x]; - [r] is the map with all the bindings of [m] whose key - is strictly greater than [x]; - [data] is [None] if [m] contains no binding for [x], - or [Some v] if [m] binds [v] to [x]. - @since 3.12.0 - *) - - val find: key -> 'a t -> 'a - (** [find x m] returns the current value of [x] in [m], - or raises [Not_found] if no binding for [x] exists. *) - - val find_opt: key -> 'a t -> 'a option - (** [find_opt x m] returns [Some v] if the current value of [x] - in [m] is [v], or [None] if no binding for [x] exists. - @since 4.05 - *) - - val find_first: f:(key -> bool) -> 'a t -> key * 'a - (** [find_first ~f m], where [f] is a monotonically increasing function, - returns the binding of [m] with the lowest key [k] such that [f k], - or raises [Not_found] if no such key exists. - - For example, [find_first (fun k -> Ord.compare k x >= 0) m] will return - the first binding [k, v] of [m] where [Ord.compare k x >= 0] - (intuitively: [k >= x]), or raise [Not_found] if [x] is greater than any - element of [m]. - - @since 4.05 + val singleton: key -> 'a -> 'a t + (** [singleton x y] returns the one-element map that contains a binding + [y] for [x]. + @since 3.12.0 *) - val find_first_opt: f:(key -> bool) -> 'a t -> (key * 'a) option - (** [find_first_opt ~f m], where [f] is a monotonically increasing function, - returns an option containing the binding of [m] with the lowest key [k] - such that [f k], or [None] if no such key exists. - @since 4.05 + val remove: key -> 'a t -> 'a t + (** [remove x m] returns a map containing the same bindings as + [m], except for [x] which is unbound in the returned map. + If [x] was not in [m], [m] is returned unchanged + (the result of the function is then physically equal to [m]). + @before 4.03 Physical equality was not ensured. *) + + val merge: + f:(key -> 'a option -> 'b option -> 'c option) -> + 'a t -> 'b t -> 'c t + (** [merge ~f m1 m2] computes a map whose keys are a subset of the keys of + [m1] and of [m2]. The presence of each such binding, and the + corresponding value, is determined with the function [f]. + In terms of the [find_opt] operation, we have + [find_opt x (merge f m1 m2) = f x (find_opt x m1) (find_opt x m2)] + for any key [x], provided that [f x None None = None]. + @since 3.12.0 *) - val find_last: f:(key -> bool) -> 'a t -> key * 'a - (** [find_last ~f m], where [f] is a monotonically decreasing function, - returns the binding of [m] with the highest key [k] such that [f k], - or raises [Not_found] if no such key exists. - @since 4.05 + val union: f:(key -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t + (** [union ~f m1 m2] computes a map whose keys are a subset of the keys + of [m1] and of [m2]. When the same binding is defined in both + arguments, the function [f] is used to combine them. + This is a special case of [merge]: [union f m1 m2] is equivalent + to [merge f' m1 m2], where + - [f' _key None None = None] + - [f' _key (Some v) None = Some v] + - [f' _key None (Some v) = Some v] + - [f' key (Some v1) (Some v2) = f key v1 v2] + + @since 4.03.0 + *) + + val compare: cmp:('a -> 'a -> int) -> 'a t -> 'a t -> int + (** Total ordering between maps. The first argument is a total ordering + used to compare data associated with equal keys in the two maps. *) + + val equal: cmp:('a -> 'a -> bool) -> 'a t -> 'a t -> bool + (** [equal ~cmp m1 m2] tests whether the maps [m1] and [m2] are + equal, that is, contain equal keys and associate them with + equal data. [cmp] is the equality predicate used to compare + the data associated with the keys. *) + + val iter: f:(key:key -> data:'a -> unit) -> 'a t -> unit + (** [iter ~f m] applies [f] to all bindings in map [m]. + [f] receives the key as first argument, and the associated value + as second argument. The bindings are passed to [f] in increasing + order with respect to the ordering over the type of the keys. *) + + val fold: f:(key:key -> data:'a -> 'b -> 'b) -> 'a t -> init:'b -> 'b + (** [fold ~f m ~init] computes [(f kN dN ... (f k1 d1 init)...)], + where [k1 ... kN] are the keys of all bindings in [m] + (in increasing order), and [d1 ... dN] are the associated data. *) + + val for_all: f:(key -> 'a -> bool) -> 'a t -> bool + (** [for_all ~f m] checks if all the bindings of the map + satisfy the predicate [f]. + @since 3.12.0 *) - val find_last_opt: f:(key -> bool) -> 'a t -> (key * 'a) option - (** [find_last_opt ~f m], where [f] is a monotonically decreasing function, - returns an option containing the binding of [m] with the highest key [k] - such that [f k], or [None] if no such key exists. - @since 4.05 + val exists: f:(key -> 'a -> bool) -> 'a t -> bool + (** [exists ~f m] checks if at least one binding of the map + satisfies the predicate [f]. + @since 3.12.0 *) - val map: f:('a -> 'b) -> 'a t -> 'b t - (** [map ~f m] returns a map with same domain as [m], where the - associated value [a] of all bindings of [m] has been - replaced by the result of the application of [f] to [a]. - The bindings are passed to [f] in increasing order - with respect to the ordering over the type of the keys. *) + val filter: f:(key -> 'a -> bool) -> 'a t -> 'a t + (** [filter ~f m] returns the map with all the bindings in [m] + that satisfy predicate [p]. If every binding in [m] satisfies [f], + [m] is returned unchanged (the result of the function is then + physically equal to [m]) + @since 3.12.0 + @before 4.03 Physical equality was not ensured. + *) - val mapi: f:(key -> 'a -> 'b) -> 'a t -> 'b t - (** Same as {!S.map}, but the function receives as arguments both the - key and the associated value for each binding of the map. *) + val filter_map: f:(key -> 'a -> 'b option) -> 'a t -> 'b t + (** [filter_map ~f m] applies the function [f] to every binding of + [m], and builds a map from the results. For each binding + [(k, v)] in the input map: + - if [f k v] is [None] then [k] is not in the result, + - if [f k v] is [Some v'] then the binding [(k, v')] + is in the output map. - (** {1 Iterators} *) + For example, the following function on maps whose values are lists + {[ + filter_map + (fun _k li -> match li with [] -> None | _::tl -> Some tl) + m + ]} + drops all bindings of [m] whose value is an empty list, and pops + the first element of each value that is non-empty. - val to_seq : 'a t -> (key * 'a) Seq.t - (** Iterate on the whole map, in ascending order of keys - @since 4.07 *) + @since 4.11.0 + *) - val to_rev_seq : 'a t -> (key * 'a) Seq.t - (** Iterate on the whole map, in descending order of keys - @since 4.12 *) + val partition: f:(key -> 'a -> bool) -> 'a t -> 'a t * 'a t + (** [partition ~f m] returns a pair of maps [(m1, m2)], where + [m1] contains all the bindings of [m] that satisfy the + predicate [f], and [m2] is the map with all the bindings of + [m] that do not satisfy [f]. + @since 3.12.0 + *) - val to_seq_from : key -> 'a t -> (key * 'a) Seq.t - (** [to_seq_from k m] iterates on a subset of the bindings of [m], - in ascending order of keys, from key [k] or above. - @since 4.07 *) + val cardinal: 'a t -> int + (** Return the number of bindings of a map. + @since 3.12.0 + *) - val add_seq : (key * 'a) Seq.t -> 'a t -> 'a t - (** Add the given bindings to the map, in order. - @since 4.07 *) + val bindings: 'a t -> (key * 'a) list + (** Return the list of all bindings of the given map. + The returned list is sorted in increasing order of keys with respect + to the ordering [Ord.compare], where [Ord] is the argument + given to {!Make}. + @since 3.12.0 + *) - val of_seq : (key * 'a) Seq.t -> 'a t - (** Build a map from the given bindings - @since 4.07 *) - end -(** Output signature of the functor {!Make}. *) + val min_binding: 'a t -> (key * 'a) + (** Return the binding with the smallest key in a given map + (with respect to the [Ord.compare] ordering), or raise + [Not_found] if the map is empty. + @since 3.12.0 + *) - module Make : functor (Ord : OrderedType) -> S + val min_binding_opt: 'a t -> (key * 'a) option + (** Return the binding with the smallest key in the given map + (with respect to the [Ord.compare] ordering), or [None] + if the map is empty. + @since 4.05 + *) + + val max_binding: 'a t -> (key * 'a) + (** Same as {!S.min_binding}, but returns the binding with + the largest key in the given map. + @since 3.12.0 + *) + + val max_binding_opt: 'a t -> (key * 'a) option + (** Same as {!S.min_binding_opt}, but returns the binding with + the largest key in the given map. + @since 4.05 + *) + + val choose: 'a t -> (key * 'a) + (** Return one binding of the given map, or raise [Not_found] if + the map is empty. Which binding is chosen is unspecified, + but equal bindings will be chosen for equal maps. + @since 3.12.0 + *) + + val choose_opt: 'a t -> (key * 'a) option + (** Return one binding of the given map, or [None] if + the map is empty. Which binding is chosen is unspecified, + but equal bindings will be chosen for equal maps. + @since 4.05 + *) + + val split: key -> 'a t -> 'a t * 'a option * 'a t + (** [split x m] returns a triple [(l, data, r)], where + [l] is the map with all the bindings of [m] whose key + is strictly less than [x]; + [r] is the map with all the bindings of [m] whose key + is strictly greater than [x]; + [data] is [None] if [m] contains no binding for [x], + or [Some v] if [m] binds [v] to [x]. + @since 3.12.0 + *) + + val find: key -> 'a t -> 'a + (** [find x m] returns the current value of [x] in [m], + or raises [Not_found] if no binding for [x] exists. *) + + val find_opt: key -> 'a t -> 'a option + (** [find_opt x m] returns [Some v] if the current value of [x] + in [m] is [v], or [None] if no binding for [x] exists. + @since 4.05 + *) + + val find_first: f:(key -> bool) -> 'a t -> key * 'a + (** [find_first ~f m], where [f] is a monotonically increasing function, + returns the binding of [m] with the lowest key [k] such that [f k], + or raises [Not_found] if no such key exists. + + For example, [find_first (fun k -> Ord.compare k x >= 0) m] will return + the first binding [k, v] of [m] where [Ord.compare k x >= 0] + (intuitively: [k >= x]), or raise [Not_found] if [x] is greater than + any element of [m]. + + @since 4.05 + *) + + val find_first_opt: f:(key -> bool) -> 'a t -> (key * 'a) option + (** [find_first_opt ~f m], where [f] is a monotonically increasing + function, returns an option containing the binding of [m] with the + lowest key [k] such that [f k], or [None] if no such key exists. + @since 4.05 + *) + + val find_last: f:(key -> bool) -> 'a t -> key * 'a + (** [find_last ~f m], where [f] is a monotonically decreasing function, + returns the binding of [m] with the highest key [k] such that [f k], + or raises [Not_found] if no such key exists. + @since 4.05 + *) + + val find_last_opt: f:(key -> bool) -> 'a t -> (key * 'a) option + (** [find_last_opt ~f m], where [f] is a monotonically decreasing + function, returns an option containing the binding of [m] with + the highest key [k] such that [f k], or [None] if no such key + exists. + @since 4.05 + *) + + val map: f:('a -> 'b) -> 'a t -> 'b t + (** [map ~f m] returns a map with same domain as [m], where the + associated value [a] of all bindings of [m] has been + replaced by the result of the application of [f] to [a]. + The bindings are passed to [f] in increasing order + with respect to the ordering over the type of the keys. *) + + val mapi: f:(key -> 'a -> 'b) -> 'a t -> 'b t + (** Same as {!S.map}, but the function receives as arguments both the + key and the associated value for each binding of the map. *) + + (** {1 Iterators} *) + + val to_seq : 'a t -> (key * 'a) Seq.t + (** Iterate on the whole map, in ascending order of keys + @since 4.07 *) + + val to_rev_seq : 'a t -> (key * 'a) Seq.t + (** Iterate on the whole map, in descending order of keys + @since 4.12 *) + + val to_seq_from : key -> 'a t -> (key * 'a) Seq.t + (** [to_seq_from k m] iterates on a subset of the bindings of [m], + in ascending order of keys, from key [k] or above. + @since 4.07 *) + + val add_seq : (key * 'a) Seq.t -> 'a t -> 'a t + (** Add the given bindings to the map, in order. + @since 4.07 *) + + val of_seq : (key * 'a) Seq.t -> 'a t + (** Build a map from the given bindings + @since 4.07 *) + end + (** Output signature of the functor {!Make}. *) + + module Make : functor (Ord : OrderedType) -> S with type key = Ord.t and type 'a t = 'a Map.Make(Ord).t -(** Functor building an implementation of the map structure - given a totally ordered type. *) + (** Functor building an implementation of the map structure + given a totally ordered type. *) end module Set : sig -(** Sets over ordered types. + (** Sets over ordered types. - This module implements the set data structure, given a total ordering - function over the set elements. All operations over sets - are purely applicative (no side-effects). - The implementation uses balanced binary trees, and is therefore - reasonably efficient: insertion and membership take time - logarithmic in the size of the set, for instance. + This module implements the set data structure, given a total ordering + function over the set elements. All operations over sets + are purely applicative (no side-effects). + The implementation uses balanced binary trees, and is therefore + reasonably efficient: insertion and membership take time + logarithmic in the size of the set, for instance. - The {!Make} functor constructs implementations for any type, given a - [compare] function. - For instance: - {[ - module IntPairs = - struct - type t = int * int - let compare (x0,y0) (x1,y1) = - match Stdlib.compare x0 x1 with - 0 -> Stdlib.compare y0 y1 - | c -> c - end + The {!Make} functor constructs implementations for any type, given a + [compare] function. + For instance: + {[ + module IntPairs = + struct + type t = int * int + let compare (x0,y0) (x1,y1) = + match Stdlib.compare x0 x1 with + 0 -> Stdlib.compare y0 y1 + | c -> c + end - module PairsSet = Set.Make(IntPairs) + module PairsSet = Set.Make(IntPairs) - let m = PairsSet.(empty |> add (2,3) |> add (5,7) |> add (11,13)) - ]} + let m = PairsSet.(empty |> add (2,3) |> add (5,7) |> add (11,13)) + ]} - This creates a new module [PairsSet], with a new type [PairsSet.t] - of sets of [int * int]. -*) + This creates a new module [PairsSet], with a new type [PairsSet.t] + of sets of [int * int]. + *) -module type OrderedType = - sig - type t + module type OrderedType = + sig + type t + (** The type of the set elements. *) + + val compare : t -> t -> int + (** A total ordering function over the set elements. + This is a two-argument function [f] such that + [f e1 e2] is zero if the elements [e1] and [e2] are equal, + [f e1 e2] is strictly negative if [e1] is smaller than [e2], + and [f e1 e2] is strictly positive if [e1] is greater than [e2]. + Example: a suitable ordering function is the generic structural + comparison function {!Stdlib.compare}. *) + end + (** Input signature of the functor {!Make}. *) + + module type S = + sig + type elt (** The type of the set elements. *) - val compare : t -> t -> int - (** A total ordering function over the set elements. - This is a two-argument function [f] such that - [f e1 e2] is zero if the elements [e1] and [e2] are equal, - [f e1 e2] is strictly negative if [e1] is smaller than [e2], - and [f e1 e2] is strictly positive if [e1] is greater than [e2]. - Example: a suitable ordering function is the generic structural - comparison function {!Stdlib.compare}. *) - end -(** Input signature of the functor {!Make}. *) + type t + (** The type of sets. *) -module type S = - sig - type elt - (** The type of the set elements. *) + val empty: t + (** The empty set. *) - type t - (** The type of sets. *) + val is_empty: t -> bool + (** Test whether a set is empty or not. *) - val empty: t - (** The empty set. *) + val mem: elt -> t -> bool + (** [mem x s] tests whether [x] belongs to the set [s]. *) - val is_empty: t -> bool - (** Test whether a set is empty or not. *) + val add: elt -> t -> t + (** [add x s] returns a set containing all elements of [s], + plus [x]. If [x] was already in [s], [s] is returned unchanged + (the result of the function is then physically equal to [s]). + @before 4.03 Physical equality was not ensured. *) - val mem: elt -> t -> bool - (** [mem x s] tests whether [x] belongs to the set [s]. *) + val singleton: elt -> t + (** [singleton x] returns the one-element set containing only [x]. *) - val add: elt -> t -> t - (** [add x s] returns a set containing all elements of [s], - plus [x]. If [x] was already in [s], [s] is returned unchanged - (the result of the function is then physically equal to [s]). - @before 4.03 Physical equality was not ensured. *) + val remove: elt -> t -> t + (** [remove x s] returns a set containing all elements of [s], + except [x]. If [x] was not in [s], [s] is returned unchanged + (the result of the function is then physically equal to [s]). + @before 4.03 Physical equality was not ensured. *) - val singleton: elt -> t - (** [singleton x] returns the one-element set containing only [x]. *) + val union: t -> t -> t + (** Set union. *) - val remove: elt -> t -> t - (** [remove x s] returns a set containing all elements of [s], - except [x]. If [x] was not in [s], [s] is returned unchanged - (the result of the function is then physically equal to [s]). - @before 4.03 Physical equality was not ensured. *) + val inter: t -> t -> t + (** Set intersection. *) - val union: t -> t -> t - (** Set union. *) + val disjoint: t -> t -> bool + (** Test if two sets are disjoint. + @since 4.08.0 *) - val inter: t -> t -> t - (** Set intersection. *) + val diff: t -> t -> t + (** Set difference: [diff s1 s2] contains the elements of [s1] + that are not in [s2]. *) - val disjoint: t -> t -> bool - (** Test if two sets are disjoint. - @since 4.08.0 *) + val compare: t -> t -> int + (** Total ordering between sets. Can be used as the ordering function + for doing sets of sets. *) - val diff: t -> t -> t - (** Set difference: [diff s1 s2] contains the elements of [s1] - that are not in [s2]. *) + val equal: t -> t -> bool + (** [equal s1 s2] tests whether the sets [s1] and [s2] are + equal, that is, contain equal elements. *) - val compare: t -> t -> int - (** Total ordering between sets. Can be used as the ordering function - for doing sets of sets. *) + val subset: t -> t -> bool + (** [subset s1 s2] tests whether the set [s1] is a subset of + the set [s2]. *) - val equal: t -> t -> bool - (** [equal s1 s2] tests whether the sets [s1] and [s2] are - equal, that is, contain equal elements. *) + val iter: f:(elt -> unit) -> t -> unit + (** [iter ~f s] applies [f] in turn to all elements of [s]. + The elements of [s] are presented to [f] in increasing order + with respect to the ordering over the type of the elements. *) - val subset: t -> t -> bool - (** [subset s1 s2] tests whether the set [s1] is a subset of - the set [s2]. *) + val map: f:(elt -> elt) -> t -> t + (** [map ~f s] is the set whose elements are [f a0],[f a1]... [f + aN], where [a0],[a1]...[aN] are the elements of [s]. - val iter: f:(elt -> unit) -> t -> unit - (** [iter ~f s] applies [f] in turn to all elements of [s]. - The elements of [s] are presented to [f] in increasing order - with respect to the ordering over the type of the elements. *) + The elements are passed to [f] in increasing order + with respect to the ordering over the type of the elements. - val map: f:(elt -> elt) -> t -> t - (** [map ~f s] is the set whose elements are [f a0],[f a1]... [f - aN], where [a0],[a1]...[aN] are the elements of [s]. + If no element of [s] is changed by [f], [s] is returned + unchanged. (If each output of [f] is physically equal to its + input, the returned set is physically equal to [s].) + @since 4.04.0 *) - The elements are passed to [f] in increasing order - with respect to the ordering over the type of the elements. + val fold: f:(elt -> 'a -> 'a) -> t -> init:'a -> 'a + (** [fold ~f s init] computes [(f xN ... (f x2 (f x1 init))...)], + where [x1 ... xN] are the elements of [s], in increasing order. *) - If no element of [s] is changed by [f], [s] is returned - unchanged. (If each output of [f] is physically equal to its - input, the returned set is physically equal to [s].) - @since 4.04.0 *) + val for_all: f:(elt -> bool) -> t -> bool + (** [for_all ~f s] checks if all elements of the set + satisfy the predicate [f]. *) - val fold: f:(elt -> 'a -> 'a) -> t -> init:'a -> 'a - (** [fold ~f s init] computes [(f xN ... (f x2 (f x1 init))...)], - where [x1 ... xN] are the elements of [s], in increasing order. *) + val exists: f:(elt -> bool) -> t -> bool + (** [exists ~f s] checks if at least one element of + the set satisfies the predicate [f]. *) - val for_all: f:(elt -> bool) -> t -> bool - (** [for_all ~f s] checks if all elements of the set - satisfy the predicate [f]. *) + val filter: f:(elt -> bool) -> t -> t + (** [filter ~f s] returns the set of all elements in [s] + that satisfy predicate [f]. If [f] satisfies every element in [s], + [s] is returned unchanged (the result of the function is then + physically equal to [s]). + @before 4.03 Physical equality was not ensured.*) - val exists: f:(elt -> bool) -> t -> bool - (** [exists ~f s] checks if at least one element of - the set satisfies the predicate [f]. *) + val filter_map: f:(elt -> elt option) -> t -> t + (** [filter_map ~f s] returns the set of all [v] such that + [f x = Some v] for some element [x] of [s]. - val filter: f:(elt -> bool) -> t -> t - (** [filter ~f s] returns the set of all elements in [s] - that satisfy predicate [f]. If [f] satisfies every element in [s], - [s] is returned unchanged (the result of the function is then - physically equal to [s]). - @before 4.03 Physical equality was not ensured.*) + For example, + {[filter_map (fun n -> if n mod 2 = 0 then Some (n / 2) else None) s]} + is the set of halves of the even elements of [s]. - val filter_map: f:(elt -> elt option) -> t -> t - (** [filter_map ~f s] returns the set of all [v] such that - [f x = Some v] for some element [x] of [s]. + If no element of [s] is changed or dropped by [f] (if + [f x = Some x] for each element [x]), then + [s] is returned unchanged: the result of the function + is then physically equal to [s]. - For example, - {[filter_map (fun n -> if n mod 2 = 0 then Some (n / 2) else None) s]} - is the set of halves of the even elements of [s]. - - If no element of [s] is changed or dropped by [f] (if - [f x = Some x] for each element [x]), then - [s] is returned unchanged: the result of the function - is then physically equal to [s]. - - @since 4.11.0 - *) - - val partition: f:(elt -> bool) -> t -> t * t - (** [partition ~f s] returns a pair of sets [(s1, s2)], where - [s1] is the set of all the elements of [s] that satisfy the - predicate [f], and [s2] is the set of all the elements of - [s] that do not satisfy [f]. *) - - val cardinal: t -> int - (** Return the number of elements of a set. *) - - val elements: t -> elt list - (** Return the list of all elements of the given set. - The returned list is sorted in increasing order with respect - to the ordering [Ord.compare], where [Ord] is the argument - given to {!Make}. *) - - val min_elt: t -> elt - (** Return the smallest element of the given set - (with respect to the [Ord.compare] ordering), or raise - [Not_found] if the set is empty. *) - - val min_elt_opt: t -> elt option - (** Return the smallest element of the given set - (with respect to the [Ord.compare] ordering), or [None] - if the set is empty. - @since 4.05 - *) - - val max_elt: t -> elt - (** Same as {!S.min_elt}, but returns the largest element of the - given set. *) - - val max_elt_opt: t -> elt option - (** Same as {!S.min_elt_opt}, but returns the largest element of the - given set. - @since 4.05 - *) - - val choose: t -> elt - (** Return one element of the given set, or raise [Not_found] if - the set is empty. Which element is chosen is unspecified, - but equal elements will be chosen for equal sets. *) - - val choose_opt: t -> elt option - (** Return one element of the given set, or [None] if - the set is empty. Which element is chosen is unspecified, - but equal elements will be chosen for equal sets. - @since 4.05 - *) - - val split: elt -> t -> t * bool * t - (** [split x s] returns a triple [(l, present, r)], where - [l] is the set of elements of [s] that are - strictly less than [x]; - [r] is the set of elements of [s] that are - strictly greater than [x]; - [present] is [false] if [s] contains no element equal to [x], - or [true] if [s] contains an element equal to [x]. *) - - val find: elt -> t -> elt - (** [find x s] returns the element of [s] equal to [x] (according - to [Ord.compare]), or raise [Not_found] if no such element - exists. - @since 4.01.0 *) - - val find_opt: elt -> t -> elt option - (** [find_opt x s] returns the element of [s] equal to [x] (according - to [Ord.compare]), or [None] if no such element - exists. - @since 4.05 *) - - val find_first: f:(elt -> bool) -> t -> elt - (** [find_first ~f s], where [f] is a monotonically increasing function, - returns the lowest element [e] of [s] such that [f e], - or raises [Not_found] if no such element exists. - - For example, [find_first (fun e -> Ord.compare e x >= 0) s] will return - the first element [e] of [s] where [Ord.compare e x >= 0] (intuitively: - [e >= x]), or raise [Not_found] if [x] is greater than any element of - [s]. - - @since 4.05 + @since 4.11.0 *) - val find_first_opt: f:(elt -> bool) -> t -> elt option - (** [find_first_opt ~f s], where [f] is a monotonically increasing function, - returns an option containing the lowest element [e] of [s] such that - [f e], or [None] if no such element exists. - @since 4.05 - *) + val partition: f:(elt -> bool) -> t -> t * t + (** [partition ~f s] returns a pair of sets [(s1, s2)], where + [s1] is the set of all the elements of [s] that satisfy the + predicate [f], and [s2] is the set of all the elements of + [s] that do not satisfy [f]. *) - val find_last: f:(elt -> bool) -> t -> elt - (** [find_last ~f s], where [f] is a monotonically decreasing function, - returns the highest element [e] of [s] such that [f e], - or raises [Not_found] if no such element exists. - @since 4.05 - *) + val cardinal: t -> int + (** Return the number of elements of a set. *) - val find_last_opt: f:(elt -> bool) -> t -> elt option - (** [find_last_opt ~f s], where [f] is a monotonically decreasing function, - returns an option containing the highest element [e] of [s] such that - [f e], or [None] if no such element exists. - @since 4.05 - *) + val elements: t -> elt list + (** Return the list of all elements of the given set. + The returned list is sorted in increasing order with respect + to the ordering [Ord.compare], where [Ord] is the argument + given to {!Make}. *) - val of_list: elt list -> t - (** [of_list l] creates a set from a list of elements. - This is usually more efficient than folding [add] over the list, - except perhaps for lists with many duplicated elements. - @since 4.02.0 *) + val min_elt: t -> elt + (** Return the smallest element of the given set + (with respect to the [Ord.compare] ordering), or raise + [Not_found] if the set is empty. *) - (** {1 Iterators} *) + val min_elt_opt: t -> elt option + (** Return the smallest element of the given set + (with respect to the [Ord.compare] ordering), or [None] + if the set is empty. + @since 4.05 + *) - val to_seq_from : elt -> t -> elt Seq.t - (** [to_seq_from x s] iterates on a subset of the elements of [s] - in ascending order, from [x] or above. - @since 4.07 *) + val max_elt: t -> elt + (** Same as {!S.min_elt}, but returns the largest element of the + given set. *) - val to_seq : t -> elt Seq.t - (** Iterate on the whole set, in ascending order - @since 4.07 *) + val max_elt_opt: t -> elt option + (** Same as {!S.min_elt_opt}, but returns the largest element of the + given set. + @since 4.05 + *) - val to_rev_seq : t -> elt Seq.t - (** Iterate on the whole set, in descending order - @since 4.12 *) + val choose: t -> elt + (** Return one element of the given set, or raise [Not_found] if + the set is empty. Which element is chosen is unspecified, + but equal elements will be chosen for equal sets. *) - val add_seq : elt Seq.t -> t -> t - (** Add the given elements to the set, in order. - @since 4.07 *) + val choose_opt: t -> elt option + (** Return one element of the given set, or [None] if + the set is empty. Which element is chosen is unspecified, + but equal elements will be chosen for equal sets. + @since 4.05 + *) - val of_seq : elt Seq.t -> t - (** Build a set from the given bindings - @since 4.07 *) - end -(** Output signature of the functor {!Make}. *) + val split: elt -> t -> t * bool * t + (** [split x s] returns a triple [(l, present, r)], where + [l] is the set of elements of [s] that are + strictly less than [x]; + [r] is the set of elements of [s] that are + strictly greater than [x]; + [present] is [false] if [s] contains no element equal to [x], + or [true] if [s] contains an element equal to [x]. *) - module Make : functor (Ord : OrderedType) -> S + val find: elt -> t -> elt + (** [find x s] returns the element of [s] equal to [x] (according + to [Ord.compare]), or raise [Not_found] if no such element + exists. + @since 4.01.0 *) + + val find_opt: elt -> t -> elt option + (** [find_opt x s] returns the element of [s] equal to [x] (according + to [Ord.compare]), or [None] if no such element + exists. + @since 4.05 *) + + val find_first: f:(elt -> bool) -> t -> elt + (** [find_first ~f s], where [f] is a monotonically increasing function, + returns the lowest element [e] of [s] such that [f e], + or raises [Not_found] if no such element exists. + + For example, [find_first (fun e -> Ord.compare e x >= 0) s] will return + the first element [e] of [s] where [Ord.compare e x >= 0] (intuitively: + [e >= x]), or raise [Not_found] if [x] is greater than any element of + [s]. + + @since 4.05 + *) + + val find_first_opt: f:(elt -> bool) -> t -> elt option + (** [find_first_opt ~f s], where [f] is a monotonically increasing + function, returns an option containing the lowest element [e] of [s] + such that [f e], or [None] if no such element exists. + @since 4.05 + *) + + val find_last: f:(elt -> bool) -> t -> elt + (** [find_last ~f s], where [f] is a monotonically decreasing function, + returns the highest element [e] of [s] such that [f e], + or raises [Not_found] if no such element exists. + @since 4.05 + *) + + val find_last_opt: f:(elt -> bool) -> t -> elt option + (** [find_last_opt ~f s], where [f] is a monotonically decreasing + function, returns an option containing the highest element [e] of [s] + such that [f e], or [None] if no such element exists. + @since 4.05 + *) + + val of_list: elt list -> t + (** [of_list l] creates a set from a list of elements. + This is usually more efficient than folding [add] over the list, + except perhaps for lists with many duplicated elements. + @since 4.02.0 *) + + (** {1 Iterators} *) + + val to_seq_from : elt -> t -> elt Seq.t + (** [to_seq_from x s] iterates on a subset of the elements of [s] + in ascending order, from [x] or above. + @since 4.07 *) + + val to_seq : t -> elt Seq.t + (** Iterate on the whole set, in ascending order + @since 4.07 *) + + val to_rev_seq : t -> elt Seq.t + (** Iterate on the whole set, in descending order + @since 4.12 *) + + val add_seq : elt Seq.t -> t -> t + (** Add the given elements to the set, in order. + @since 4.07 *) + + val of_seq : elt Seq.t -> t + (** Build a set from the given bindings + @since 4.07 *) + end + (** Output signature of the functor {!Make}. *) + + module Make : functor (Ord : OrderedType) -> S with type elt = Ord.t and type t = Set.Make(Ord).t -(** Functor building an implementation of the set structure - given a totally ordered type. *) + (** Functor building an implementation of the set structure + given a totally ordered type. *) end diff --git a/stdlib/set.mli b/stdlib/set.mli index a6c6f266d..29e9f5188 100644 --- a/stdlib/set.mli +++ b/stdlib/set.mli @@ -257,9 +257,9 @@ module type S = *) val find_first_opt: (elt -> bool) -> t -> elt option - (** [find_first_opt f s], where [f] is a monotonically increasing function, - returns an option containing the lowest element [e] of [s] such that - [f e], or [None] if no such element exists. + (** [find_first_opt f s], where [f] is a monotonically increasing + function, returns an option containing the lowest element [e] of [s] + such that [f e], or [None] if no such element exists. @since 4.05 *) @@ -271,9 +271,9 @@ module type S = *) val find_last_opt: (elt -> bool) -> t -> elt option - (** [find_last_opt f s], where [f] is a monotonically decreasing function, - returns an option containing the highest element [e] of [s] such that - [f e], or [None] if no such element exists. + (** [find_last_opt f s], where [f] is a monotonically decreasing + function, returns an option containing the highest element [e] of [s] + such that [f e], or [None] if no such element exists. @since 4.05 *) diff --git a/stdlib/templates/hashtbl.template.mli b/stdlib/templates/hashtbl.template.mli index f569d5aee..bbb32b1a0 100644 --- a/stdlib/templates/hashtbl.template.mli +++ b/stdlib/templates/hashtbl.template.mli @@ -50,13 +50,13 @@ val create : ?random: (* thwart tools/unlabel *) bool -> int -> ('a, 'b) t A hash table that is created with [~random] set to [true] uses the seeded hash function {!seeded_hash} with a seed that is randomly chosen at hash - table creation time. In effect, the hash function used is randomly selected - among [2^{30}] different hash functions. All these hash functions have - different collision patterns, rendering ineffective the denial-of-service - attack described above. However, because of randomization, enumerating all - elements of the hash table using {!fold} or {!iter} is no longer - deterministic: elements are enumerated in different orders at different runs - of the program. + table creation time. In effect, the hash function used is randomly + selected among [2^{30}] different hash functions. All these hash + functions have different collision patterns, rendering ineffective the + denial-of-service attack described above. However, because of + randomization, enumerating all elements of the hash table using {!fold} + or {!iter} is no longer deterministic: elements are enumerated in + different orders at different runs of the program. If no [~random] parameter is given, hash tables are created in non-random mode by default. This default can be changed @@ -136,7 +136,8 @@ val iter : f:(key:'a -> data:'b -> unit) -> ('a, 'b) t -> unit by [f] during the iteration. *) -val filter_map_inplace: f:(key:'a -> data:'b -> 'b option) -> ('a, 'b) t -> unit +val filter_map_inplace: f:(key:'a -> data:'b -> 'b option) -> ('a, 'b) t -> + unit (** [Hashtbl.filter_map_inplace ~f tbl] applies [f] to all bindings in table [tbl] and update each binding depending on the result of [f]. If [f] returns [None], the binding is discarded. If it @@ -346,7 +347,8 @@ module type S = val replace : 'a t -> key:key -> data:'a -> unit val mem : 'a t -> key -> bool val iter : f:(key:key -> data:'a -> unit) -> 'a t -> unit - val filter_map_inplace: f:(key:key -> data:'a -> 'a option) -> 'a t -> unit + val filter_map_inplace: f:(key:key -> data:'a -> 'a option) -> 'a t -> + unit (** @since 4.03.0 *) val fold : f:(key:key -> data:'a -> 'b -> 'b) -> 'a t -> init:'b -> 'b @@ -420,7 +422,8 @@ module type SeededS = val replace : 'a t -> key:key -> data:'a -> unit val mem : 'a t -> key -> bool val iter : f:(key:key -> data:'a -> unit) -> 'a t -> unit - val filter_map_inplace: f:(key:key -> data:'a -> 'a option) -> 'a t -> unit + val filter_map_inplace: f:(key:key -> data:'a -> 'a option) -> 'a t -> + unit (** @since 4.03.0 *) val fold : f:(key:key -> data:'a -> 'b -> 'b) -> 'a t -> init:'b -> 'b diff --git a/stdlib/templates/map.template.mli b/stdlib/templates/map.template.mli index 4874d9584..68a27e827 100644 --- a/stdlib/templates/map.template.mli +++ b/stdlib/templates/map.template.mli @@ -103,8 +103,8 @@ module type S = *) val singleton: key -> 'a -> 'a t - (** [singleton x y] returns the one-element map that contains a binding [y] - for [x]. + (** [singleton x y] returns the one-element map that contains a binding + [y] for [x]. @since 3.12.0 *) @@ -116,7 +116,8 @@ module type S = @before 4.03 Physical equality was not ensured. *) val merge: - f:(key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t + f:(key -> 'a option -> 'b option -> 'c option) -> + 'a t -> 'b t -> 'c t (** [merge ~f m1 m2] computes a map whose keys are a subset of the keys of [m1] and of [m2]. The presence of each such binding, and the corresponding value, is determined with the function [f]. @@ -291,16 +292,16 @@ module type S = For example, [find_first (fun k -> Ord.compare k x >= 0) m] will return the first binding [k, v] of [m] where [Ord.compare k x >= 0] - (intuitively: [k >= x]), or raise [Not_found] if [x] is greater than any - element of [m]. + (intuitively: [k >= x]), or raise [Not_found] if [x] is greater than + any element of [m]. @since 4.05 *) val find_first_opt: f:(key -> bool) -> 'a t -> (key * 'a) option - (** [find_first_opt ~f m], where [f] is a monotonically increasing function, - returns an option containing the binding of [m] with the lowest key [k] - such that [f k], or [None] if no such key exists. + (** [find_first_opt ~f m], where [f] is a monotonically increasing + function, returns an option containing the binding of [m] with the + lowest key [k] such that [f k], or [None] if no such key exists. @since 4.05 *) @@ -312,9 +313,10 @@ module type S = *) val find_last_opt: f:(key -> bool) -> 'a t -> (key * 'a) option - (** [find_last_opt ~f m], where [f] is a monotonically decreasing function, - returns an option containing the binding of [m] with the highest key [k] - such that [f k], or [None] if no such key exists. + (** [find_last_opt ~f m], where [f] is a monotonically decreasing + function, returns an option containing the binding of [m] with + the highest key [k] such that [f k], or [None] if no such key + exists. @since 4.05 *) diff --git a/stdlib/templates/moreLabels.template.mli b/stdlib/templates/moreLabels.template.mli index f708a58a8..3efb4ebe1 100644 --- a/stdlib/templates/moreLabels.template.mli +++ b/stdlib/templates/moreLabels.template.mli @@ -18,12 +18,18 @@ (** Extra labeled libraries. - This meta-module provides labelized version of the {!Hashtbl}, - {!Map} and {!Set} modules. + This meta-module provides labelized versions of the {!Hashtbl}, {!Map} and + {!Set} modules. - They only differ by their labels. They are provided to help - porting from previous versions of OCaml. - The contents of this module are subject to change. + This module is intended to be used through [open MoreLabels] which replaces + {!Hashtbl}, {!Map}, and {!Set} with their labeled counterparts. + + For example: + {[ + open MoreLabels + + Hashtbl.iter ~f:(fun ~key ~data -> g key data) table + ]} *) module Hashtbl : sig diff --git a/stdlib/templates/set.template.mli b/stdlib/templates/set.template.mli index bcbf498a3..55eda0b3d 100644 --- a/stdlib/templates/set.template.mli +++ b/stdlib/templates/set.template.mli @@ -257,9 +257,9 @@ module type S = *) val find_first_opt: f:(elt -> bool) -> t -> elt option - (** [find_first_opt ~f s], where [f] is a monotonically increasing function, - returns an option containing the lowest element [e] of [s] such that - [f e], or [None] if no such element exists. + (** [find_first_opt ~f s], where [f] is a monotonically increasing + function, returns an option containing the lowest element [e] of [s] + such that [f e], or [None] if no such element exists. @since 4.05 *) @@ -271,9 +271,9 @@ module type S = *) val find_last_opt: f:(elt -> bool) -> t -> elt option - (** [find_last_opt ~f s], where [f] is a monotonically decreasing function, - returns an option containing the highest element [e] of [s] such that - [f e], or [None] if no such element exists. + (** [find_last_opt ~f s], where [f] is a monotonically decreasing + function, returns an option containing the highest element [e] of [s] + such that [f e], or [None] if no such element exists. @since 4.05 *) diff --git a/tools/unlabel b/tools/unlabel index 6983bf957..6ad915e5e 100755 --- a/tools/unlabel +++ b/tools/unlabel @@ -34,9 +34,12 @@ LABLABREGEX="s/\([a-z_]+:([a-z\('])/\(\1/g" #OCamldoc code section with ] TILDEREGEX="s/~([a-z_]*[ \]])/\1/g" -# @sinceunlabeled --> @since +#@sinceunlabeled --> @since SINCEREGEX="s/sinceunlabeled/since/g" +#Indent a non-blank line by two characters, for moreLabels templates +INDENTREGEX="s/^(.+)$/ \1/m" + #Stdlib perl -p -e "$LABREGEX" stdlib/listLabels.mli > stdlib/list.temp.mli perl -p -e "$LABREGEX" stdlib/arrayLabels.mli > stdlib/array.temp.mli @@ -76,13 +79,21 @@ perl -p -e "$TILDEREGEX" stdlib/set.2temp.mli > stdlib/set.mli #(No @since problems in MoreLabels) +#Indent the labeled modules +perl -p -e "$INDENTREGEX" stdlib/templates/hashtbl.template.mli > \ + stdlib/templates/hashtbl.template.temp.mli +perl -p -e "$INDENTREGEX" stdlib/templates/map.template.mli > \ + stdlib/templates/map.template.temp.mli +perl -p -e "$INDENTREGEX" stdlib/templates/set.template.mli > \ + stdlib/templates/set.template.temp.mli + #Substitute the labeled modules in to moreLabels.mli perl -p -e\ - 's/HASHTBL/`tail -n +19 stdlib\/templates\/hashtbl.template.mli`/e' \ + 's/HASHTBL/`tail -n +19 stdlib\/templates\/hashtbl.template.temp.mli`/e' \ stdlib/templates/moreLabels.template.mli > stdlib/moreLabels.temp.mli -perl -p -e 's/MAP/`tail -n +19 stdlib\/templates\/map.template.mli`/e' \ +perl -p -e 's/MAP/`tail -n +19 stdlib\/templates\/map.template.temp.mli`/e' \ stdlib/moreLabels.temp.mli > stdlib/moreLabels.2temp.mli -perl -p -e 's/SET/`tail -n +19 stdlib\/templates\/set.template.mli`/e' \ +perl -p -e 's/SET/`tail -n +19 stdlib\/templates\/set.template.temp.mli`/e' \ stdlib/moreLabels.2temp.mli > stdlib/moreLabels.mli #Fix up with templates in tools/unlabel-patches @@ -126,3 +137,4 @@ perl -p -e 's/ = Unix.LargeFile.stats//' \ #Clean up rm -f stdlib/*temp.mli rm -f otherlibs/unix/*temp.mli +rm -f stdlib/templates/*temp.mli