From 7913415c7ec15cf9ca95a87d8f72258d7c02681f Mon Sep 17 00:00:00 2001 From: Dorian Lesbre Date: Thu, 18 Jul 2024 14:27:17 +0200 Subject: [PATCH] Revert "Fix links to Sigs module" This reverts commit 24f001dc2e4cc35097dfcee0ca041f5ee6fa0fab. --- src/PatriciaTree.mli | 8 +- src/functors.mli | 30 +++---- src/index.mld | 73 ++++++++-------- src/key_value.mli | 16 ++-- src/sigs.ml | 204 +++++++++++++++++++++---------------------- 5 files changed, 164 insertions(+), 167 deletions(-) diff --git a/src/PatriciaTree.mli b/src/PatriciaTree.mli index e8fccb0..bc64a71 100644 --- a/src/PatriciaTree.mli +++ b/src/PatriciaTree.mli @@ -19,8 +19,6 @@ (* for more details (enclosed in the file LICENSE). *) (**************************************************************************) -exception Not_found - (** Association maps from key to values, and sets, implemented with Patricia Trees, allowing fast merge operations by making use of physical equality between subtrees; and custom implementation of @@ -99,8 +97,8 @@ exception Not_found notably (key,value) pairs or different types to be in the same map, or to choose the memory representation of the nodes of the tree.} - {- Some operations like {{!Sigs.BASE_MAP.pop_unsigned_minimum}[pop_unsigned_minimum]} and - {{!Sigs.BASE_MAP.pop_unsigned_maximum}[pop_unsigned_maximum]} make our Set + {- Some operations like {{!BASE_MAP.pop_unsigned_minimum}[pop_unsigned_minimum]} and + {{!BASE_MAP.pop_unsigned_maximum}[pop_unsigned_maximum]} make our Set suitable as priority queue (but remember that each element in the queue must map to a distinct integer, and that using the {{!unsigned_lt}unsigned order} means elements with negative priority are seen as greater than elements with @@ -136,7 +134,7 @@ include module type of Ints include module type of Key_value (** {1:node_impl Some implementations of NODE} *) -(** We provide a few different implementations of {!Sigs.NODE}, the internal representation +(** We provide a few different implementations of {!NODE}, the internal representation of a PatriciaTree's nodes. They can be used with the {!MakeCustomMap}, {!MakeCustomSet}, {!MakeCustomHeterogeneousMap} and {!MakeCustomHeterogeneousSet} functors to build maps and sets with custom diff --git a/src/functors.mli b/src/functors.mli index 1aafdc4..8f9a659 100644 --- a/src/functors.mli +++ b/src/functors.mli @@ -67,9 +67,9 @@ module MakeHeterogeneousMap(Key: HETEROGENEOUS_KEY)(Value: HETEROGENEOUS_VALUE) disk, lazy evaluation and/or caching, adding size information for constant time [cardinal] functions, etc. - See {!node_impl} for the provided implementations of {!Sigs.NODE}, or create your own. *) + See {!node_impl} for the provided implementations of {!NODE}, or create your own. *) -(** Create a homogeneous map with a custom {!Sigs.NODE}. Also allows +(** Create a homogeneous map with a custom {!NODE}. Also allows customizing the map values *) module MakeCustomMap (Key: KEY) @@ -81,7 +81,7 @@ module MakeCustomMap and type 'm t = 'm Node.t -(** Create a homogeneous set with a custom {!Sigs.NODE}. +(** Create a homogeneous set with a custom {!NODE}. @since v0.10.0 *) module MakeCustomSet (Key: KEY) @@ -90,7 +90,7 @@ module MakeCustomSet with type elt = Key.t and type 'a BaseMap.t = 'a Node.t -(** Create an heterogeneous map with a custom {!Sigs.NODE}. *) +(** Create an heterogeneous map with a custom {!NODE}. *) module MakeCustomHeterogeneousMap (Key: HETEROGENEOUS_KEY) (Value: HETEROGENEOUS_VALUE) @@ -100,7 +100,7 @@ module MakeCustomHeterogeneousMap and type ('k,'m) value = ('k,'m) Value.t and type 'm t = 'm Node.t -(** Create an heterogeneous set with a custom {!Sigs.NODE}. +(** Create an heterogeneous set with a custom {!NODE}. @since v0.10.0 *) module MakeCustomHeterogeneousSet (Key: HETEROGENEOUS_KEY) @@ -115,10 +115,10 @@ module MakeCustomHeterogeneousSet if so they return it, else they return a new node with a new number. With this unique numbering: - [equal] and [compare] become constant time operations; - - two maps with the same bindings (where keys are compared by {!Sigs.KEY.to_int} and - values by {!Sigs.HASHED_VALUE.polyeq}) will always be physically equal; - - functions that benefit from sharing, like {!Sigs.BASE_MAP.idempotent_union} and - {!Sigs.BASE_MAP.idempotent_inter} will see improved performance; + - two maps with the same bindings (where keys are compared by {!KEY.to_int} and + values by {!HASHED_VALUE.polyeq}) will always be physically equal; + - functions that benefit from sharing, like {!BASE_MAP.idempotent_union} and + {!BASE_MAP.idempotent_inter} will see improved performance; - constructors are slightly slower, as they now require a hash-table lookup; - memory usage is increased: nodes store their tags inside themselves, and a global hash-table of all built nodes must be maintained. @@ -126,9 +126,9 @@ module MakeCustomHeterogeneousSet as only one will be kept in memory. - hash-consed maps assume their keys and values are immutable, where regular maps can mutate values freely; - - {b WARNING:} when using physical equality as {!Sigs.HASHED_VALUE.polyeq}, some + - {b WARNING:} when using physical equality as {!HASHED_VALUE.polyeq}, some {b maps of different types may be given the same identifier}. See the end of - the documentation of {!Sigs.HASHED_VALUE.polyeq} for details. + the documentation of {!HASHED_VALUE.polyeq} for details. Note that this is the case in the default implementations {!HashedValue} and {!HeterogeneousHashedValue}. @@ -137,7 +137,7 @@ module MakeCustomHeterogeneousSet twice with same arguments will lead to two numbering systems for identifiers, and thus the types should not be considered compatible. *) -(** Hash-consed version of {!Sigs.MAP}. See {!hash_consed} for the differences between +(** Hash-consed version of {!MAP}. See {!hash_consed} for the differences between hash-consed and non hash-consed maps. This is a generative functor, as calling it creates a new hash-table to store @@ -153,7 +153,7 @@ module MakeHashconsedMap(Key: KEY)(Value: HASHED_VALUE)() : sig include HASH_CONSED_OPERATIONS with type 'a t := 'a t (** @inline *) end -(** Hash-consed version of {!Sigs.SET}. See {!hash_consed} for the differences between +(** Hash-consed version of {!SET}. See {!hash_consed} for the differences between hash-consed and non hash-consed sets. This is a generative functor, as calling it creates a new hash-table to store @@ -169,7 +169,7 @@ module MakeHashconsedSet(Key: KEY)() : sig include HASH_CONSED_OPERATIONS with type 'a t := t (** @inline *) end -(** Hash-consed version of {!Sigs.HETEROGENEOUS_SET}. See {!hash_consed} for the differences between +(** Hash-consed version of {!HETEROGENEOUS_SET}. See {!hash_consed} for the differences between hash-consed and non hash-consed sets. This is a generative functor, as calling it creates a new hash-table to store @@ -185,7 +185,7 @@ module MakeHashconsedHeterogeneousSet(Key: HETEROGENEOUS_KEY)() : sig include HASH_CONSED_OPERATIONS with type 'a t := t (** @inline *) end -(** Hash-consed version of {!Sigs.HETEROGENEOUS_MAP}. See {!hash_consed} for the differences between +(** Hash-consed version of {!HETEROGENEOUS_MAP}. See {!hash_consed} for the differences between hash-consed and non hash-consed maps. This is a generative functor, as calling it creates a new hash-table to store diff --git a/src/index.mld b/src/index.mld index bff1873..2f103d3 100644 --- a/src/index.mld +++ b/src/index.mld @@ -46,8 +46,8 @@ See the {{!examples}examples} to jump right into using this library. using the same function names when possible and the same convention for order of arguments. This should allow switching to and from Patricia Tree with minimal effort.} -{li The functor parameters ({{!PatriciaTree.Sigs.KEY}[Sigs.KEY]} module) requires an injective [to_int : t -> int] - function instead of a [compare] function. {{!PatriciaTree.Sigs.KEY.to_int}[Sigs.KEY.to_int]} should be fast, +{li The functor parameters ({{!PatriciaTree.KEY}[KEY]} module) requires an injective [to_int : t -> int] + function instead of a [compare] function. {{!PatriciaTree.KEY.to_int}[KEY.to_int]} should be fast, and injective. This works well with {{: https://en.wikipedia.org/wiki/Hash_consing}hash-consed} types.} {li The Patricia Tree representation is stable, contrary to maps, inserting nodes @@ -71,8 +71,8 @@ See the {{!examples}examples} to jump right into using this library. {{: https://www.cs.tufts.edu/comp/150FP/archive/jan-midtgaard/qc-patricia.pdf}{i QuickChecking Patricia Trees}} by Jan Mitgaard. - It also affects functions like {{!PatriciaTree.Sigs.BASE_MAP.unsigned_min_binding}[unsigned_min_binding]} - and {{!PatriciaTree.Sigs.BASE_MAP.pop_unsigned_minimum}[pop_unsigned_minimum]}. They will return the smallest + It also affects functions like {{!PatriciaTree.BASE_MAP.unsigned_min_binding}[unsigned_min_binding]} + and {{!PatriciaTree.BASE_MAP.pop_unsigned_minimum}[pop_unsigned_minimum]}. They will return the smallest positive integer of both positive and negative keys are present; and not the smallest negative, as one might expect.} {li Supports generic maps and sets: a ['m map] that maps ['k key] to [('k, 'm) value]. @@ -80,11 +80,11 @@ See the {{!examples}examples} to jump right into using this library. for the type of keys. This is also sometimes called a dependent map.} {li Allows easy and fast operations across different types of maps and set which have the same type of keys (e.g. an intersection between a map and a set).} -{li Multiple choices for internal representation ({{!PatriciaTree.Sigs.NODE}[Sigs.NODE]}), which allows for efficient +{li Multiple choices for internal representation ({{!PatriciaTree.NODE}[NODE]}), which allows for efficient storage (no need to store a value for sets), or using weak nodes only (values removed from the tree if no other pointer to it exists). This system can also be extended to store size information in nodes if needed.} -{li Exposes a common interface ({!type:PatriciaTree.Sigs.NODE.view}) to allow users to write their own pattern - matching on the tree structure without depending on the {{!PatriciaTree.Sigs.NODE}[Sigs.NODE]} being used.} +{li Exposes a common interface ({!type:PatriciaTree.NODE.view}) to allow users to write their own pattern + matching on the tree structure without depending on the {{!PatriciaTree.NODE}[NODE]} being used.} {li Additionally, hashconsed versions of heterogeneous/homogeneous maps/sets are available. These provide constant time equality and comparison, and ensure maps/set with the same constants are always physically equal. It comes at the cost @@ -101,17 +101,17 @@ The functors used to build maps and sets are the following: {li For homogeneous (non-generic) maps and sets: {{!PatriciaTree.MakeMap}[MakeMap]} and {{!PatriciaTree.MakeSet}[MakeSet]}. These are similar to the standard library's maps and sets. {@ocaml skip[ - module MakeMap(Key: Sigs.KEY) : Sigs.MAP with type key = Key.t - module MakeSet(Key: Sigs.KEY) : Sigs.SET with type elt = Key.t + module MakeMap(Key: KEY) : MAP with type key = Key.t + module MakeSet(Key: KEY) : SET with type elt = Key.t ]}} {li For Heterogeneous (generic) maps and sets: {{!PatriciaTree.MakeHeterogeneousMap}[MakeHeterogeneousMap]} and {{!PatriciaTree.MakeHeterogeneousSet}[MakeHeterogeneousSet]}. {@ocaml skip[ - module MakeHeterogeneousMap(Key: Sigs.HETEROGENEOUS_KEY)(Value: Sigs.HETEROGENEOUS_VALUE) : + module MakeHeterogeneousMap(Key: HETEROGENEOUS_KEY)(Value: HETEROGENEOUS_VALUE) : HETEROGENEOUS_MAP with type 'a key = 'a Key.t and type ('k,'m) value = ('k,'m) Value.t - module MakeHeterogeneousSet(Key: Sigs.HETEROGENEOUS_KEY) : Sigs.HETEROGENEOUS_SET + module MakeHeterogeneousSet(Key: HETEROGENEOUS_KEY) : HETEROGENEOUS_SET with type 'a elt = 'a Key.t ]}} {li @@ -120,16 +120,16 @@ The functors used to build maps and sets are the following: {{!PatriciaTree.MakeHashconsedHeterogeneousMap}[MakeHashconsedHeterogeneousMap]} and {{!PatriciaTree.MakeHashconsedHeterogeneousSet}[MakeHashconsedHeterogeneousSet]}. These uniquely number their nodes, which means: - [equal] and [compare] become constant time operations; - - two maps with the same bindings (where keys are compared by {{!PatriciaTree.Sigs.KEY.to_int}[Sigs.KEY.to_int]} and - values by {{!PatriciaTree.Sigs.HASHED_VALUE.polyeq}[Sigs.HASHED_VALUE.polyeq]}) will always be physically equal; + - two maps with the same bindings (where keys are compared by {{!PatriciaTree.KEY.to_int}[KEY.to_int]} and + values by {{!PatriciaTree.HASHED_VALUE.polyeq}[HASHED_VALUE.polyeq]}) will always be physically equal; - functions that benefit from sharing will see improved performance; - constructors are slightly slower, as they now require a hash-table lookup; - memory usage is increased: nodes store their tags inside themselves, and a global hash-table of all built nodes must be maintained; - hash-consed maps assume their values are immutable; - - {b WARNING:} when using physical equality as {{!PatriciaTree.Sigs.HASHED_VALUE.polyeq}[Sigs.HASHED_VALUE.polyeq]}, some maps of different + - {b WARNING:} when using physical equality as {{!PatriciaTree.HASHED_VALUE.polyeq}[HASHED_VALUE.polyeq]}, some maps of different types may be given the same identifier. See the end of - the documentation of {{!PatriciaTree.Sigs.HASHED_VALUE.polyeq}[Sigs.HASHED_VALUE.polyeq]} for details. + the documentation of {{!PatriciaTree.HASHED_VALUE.polyeq}[HASHED_VALUE.polyeq]} for details. Note that this is the case in the default implementations {{!PatriciaTree.HashedValue}[HashedValue]} and {{!PatriciaTree.HeterogeneousHashedValue}[HeterogeneousHashedValue]}. @@ -141,10 +141,9 @@ The functors used to build maps and sets are the following: {2 Interfaces} -Here is a brief overview of the various module types of our library. They are placed -inside the {{!PatriciaTree.Sigs}[Sigs]} module: +Here is a brief overview of the various module types of our library: {ul -{li {{!PatriciaTree.Sigs.BASE_MAP}[BASE_MAP]}: the underlying module type of all our trees (maps end sets). It +{li {{!PatriciaTree.BASE_MAP}[BASE_MAP]}: the underlying module type of all our trees (maps end sets). It represents a ['b map] binding ['a key] to [('a,'b) value], as well as all functions needed to manipulate them. @@ -152,26 +151,26 @@ inside the {{!PatriciaTree.Sigs}[Sigs]} module: unified representation, useful for cross map operations. However, for practical purposes, it is often best to use the more specific interfaces: {ul - {li {{!PatriciaTree.Sigs.HETEROGENEOUS_MAP}[HETEROGENEOUS_MAP]} for heterogeneous maps (this is just {{!PatriciaTree.Sigs.BASE_MAP}[BASE_MAP]} with a + {li {{!PatriciaTree.HETEROGENEOUS_MAP}[HETEROGENEOUS_MAP]} for heterogeneous maps (this is just {{!PatriciaTree.BASE_MAP}[BASE_MAP]} with a [WithForeign] functor).} - {li {{!PatriciaTree.Sigs.MAP}[MAP]} for homogeneous maps, this interface is close to {{: https://ocaml.org/api/Map.S.html}[Stdlib.Map.S]}.} - {li {{!PatriciaTree.Sigs.HETEROGENEOUS_SET}[HETEROGENEOUS_SET]} for heterogeneous sets (sets of ['a elt]). These are just + {li {{!PatriciaTree.MAP}[MAP]} for homogeneous maps, this interface is close to {{: https://ocaml.org/api/Map.S.html}[Stdlib.Map.S]}.} + {li {{!PatriciaTree.HETEROGENEOUS_SET}[HETEROGENEOUS_SET]} for heterogeneous sets (sets of ['a elt]). These are just maps to [unit], but with a custom node representation to avoid storing [unit] in nodes.} - {li {{!PatriciaTree.Sigs.SET}[SET]} for homogeneous sets, this interface is close to {{: https://ocaml.org/api/Set.S.html}[Stdlib.Set.S]}.} + {li {{!PatriciaTree.SET}[SET]} for homogeneous sets, this interface is close to {{: https://ocaml.org/api/Set.S.html}[Stdlib.Set.S]}.} }} -{li The parameter of our functor are either {{!PatriciaTree.Sigs.KEY}[KEY]} or {{!PatriciaTree.Sigs.HETEROGENEOUS_KEY}[HETEROGENEOUS_KEY]}. +{li The parameter of our functor are either {{!PatriciaTree.KEY}[KEY]} or {{!PatriciaTree.HETEROGENEOUS_KEY}[HETEROGENEOUS_KEY]}. These just consist of a type, a (polymorphic) equality function, and an injective [to_int] coercion. - The heterogeneous map functor also has a {{!PatriciaTree.Sigs.HETEROGENEOUS_VALUE}[HETEROGENEOUS_VALUE]} parameter to specify the + The heterogeneous map functor also has a {{!PatriciaTree.HETEROGENEOUS_VALUE}[HETEROGENEOUS_VALUE]} parameter to specify the [('a, 'b) value] type.} {li The internal representations of our tree can be customized to use different - internal {{!PatriciaTree.Sigs.NODE}[NODE]}. Each node come with its own private constructors and destructors, - as well as a cast to a uniform {{!type:PatriciaTree.Sigs.NODE.view}[NODE.view]} type used for pattern matching. + internal {{!PatriciaTree.NODE}[NODE]}. Each node come with its own private constructors and destructors, + as well as a cast to a uniform {{!type:PatriciaTree.NODE.view}[NODE.view]} type used for pattern matching. A number of implementations are provided: - - {{!PatriciaTree.SimpleNode}[SimpleNode]}: exactly the {{!type:PatriciaTree.Sigs.NODE.view}[NODE.view]} type; + - {{!PatriciaTree.SimpleNode}[SimpleNode]}: exactly the {{!type:PatriciaTree.NODE.view}[NODE.view]} type; - {{!PatriciaTree.WeakNode}[WeakNode]}: only store weak pointer to its elements; - {{!PatriciaTree.NodeWithId}[NodeWithId]}: node which contains a unique identifier; - {{!PatriciaTree.SetNode}[SetNode]}: optimized for sets, doesn't store the [unit] value; @@ -204,7 +203,7 @@ Here is a small example of a non-generic map: {ol {li Start by creating a key module. We use [type int] for keys in this example, but you can use any type, so long as it supports an efficient and injective - {{!PatriciaTree.Sigs.KEY.to_int}[to_int]} function. + {{!PatriciaTree.KEY.to_int}[to_int]} function. {@ocaml[ module IntKey : PatriciaTree.KEY with type t = int = struct type t = int @@ -213,9 +212,9 @@ Here is a small example of a non-generic map: ]}} {li Use it to instanciate the map/set functors: {[ - module IMap : PatriciaTree.Sigs.MAP with type key = int + module IMap : PatriciaTree.MAP with type key = int = PatriciaTree.MakeMap(IntKey) - module ISet : PatriciaTree.Sigs.SET with type elt = int + module ISet : PatriciaTree.SET with type elt = int = PatriciaTree.MakeSet(IntKey) ]}} {li You can now use it as you would any other map, most of the interface is @@ -230,8 +229,8 @@ Here is a small example of a non-generic map: IMap.add 3 "how do you do?";; val map : string IMap.t = ]} - (We also have {{!PatriciaTree.Sigs.MAP.of_list}[of_list]} and - {{!PatriciaTree.Sigs.MAP.of_seq}[of_seq]} functions for quick initialization) + (We also have {{!PatriciaTree.MAP.of_list}[of_list]} and + {{!PatriciaTree.MAP.of_seq}[of_seq]} functions for quick initialization) {[ # IMap.find 1 map;; - : string = "hello" @@ -241,7 +240,7 @@ Here is a small example of a non-generic map: ]}} {li The strength of Patricia Tree is the speedup of operations on multiple maps with common subtrees. For example, in the following, the - {{!PatriciaTree.Sigs.MAP.idempotent_inter_filter}[idempotent_inter_filter]} function + {{!PatriciaTree.MAP.idempotent_inter_filter}[idempotent_inter_filter]} function will skip recursive calls to physically equal subtrees (kept as-is in the intersection). This allows faster than [O(n)] intersections. {[ @@ -282,7 +281,7 @@ Here is a small example of a non-generic map: cheap equality test between maps), use the provided {{!PatriciaTree.section-hash_consed}hash-consed maps and sets}.} {li Our library also allows cross map/set operations through the - {{!PatriciaTree.Sigs.MAP.WithForeign}[WithForeign]} functors: + {{!PatriciaTree.MAP.WithForeign}[WithForeign]} functors: {[ module CrossOperations = IMap.WithForeign(ISet.BaseMap) ]} @@ -318,10 +317,10 @@ liberty of having a generic type as a key. | G_Addition : int expr * int expr -> int expr | G_Equal : 'a expr * 'a expr -> bool expr ]} - We can create our {{!PatriciaTree.Sigs.HETEROGENEOUS_KEY}[Sigs.HETEROGENEOUS_KEY]} functor + We can create our {{!PatriciaTree.HETEROGENEOUS_KEY}[HETEROGENEOUS_KEY]} functor parameter using this type as follows: {[ - module Expr : PatriciaTree.Sigs.HETEROGENEOUS_KEY with type 'a t = 'a expr = struct + module Expr : PatriciaTree.HETEROGENEOUS_KEY with type 'a t = 'a expr = struct type 'a t = 'a expr (** Injective, so long as expressions are small enough @@ -413,7 +412,7 @@ away as we would like a bit more time using this library before doing so. There is a bug in the OCaml typechecker which prevents us from directly defining non-generic maps as instances of generic maps. To avoid this, non-generic maps -use a separate value type {{!PatriciaTree.Sigs.snd}[('a, 'b) snd]} (instead of just using ['b]) +use a separate value type {{!PatriciaTree.snd}[('a, 'b) snd]} (instead of just using ['b]) {[ type (_, 'b) snd = Snd of 'b [@@unboxed] ]} diff --git a/src/key_value.mli b/src/key_value.mli index 4280c36..f2a65f3 100644 --- a/src/key_value.mli +++ b/src/key_value.mli @@ -22,11 +22,11 @@ open Sigs module Value : VALUE with type 'a t = 'a -(** Default implementation of {!Sigs.VALUE}, used in {!MakeMap}. +(** Default implementation of {!VALUE}, used in {!MakeMap}. @since 0.10.0 *) module HomogeneousValue : HETEROGENEOUS_VALUE with type ('a,'map) t = 'map -(** Default implementation of {!Sigs.HETEROGENEOUS_VALUE}, to use when the type of the +(** Default implementation of {!HETEROGENEOUS_VALUE}, to use when the type of the value in a heterogeneous map does not depend on the type of the key, only on the type of the map. *) @@ -38,30 +38,30 @@ module WrappedHomogeneousValue : HETEROGENEOUS_VALUE with type ('a,'map) t = ('a and {{: https://github.com/ocaml/ocaml/issues/13292}the github issue}. *) module HashedValue : HASHED_VALUE with type 'a t = 'a -(** Generic implementation of {!Sigs.HASHED_VALUE}. +(** Generic implementation of {!HASHED_VALUE}. Uses {{: https://ocaml.org/api/Hashtbl.html#VALhash}[Hashtbl.hash]} for hashing and physical equality for equality. Note that this may lead to maps of different types having the same identifier - ({!MakeHashconsedMap.to_int}), see the documentation of {!Sigs.HASHED_VALUE.polyeq} + ({!MakeHashconsedMap.to_int}), see the documentation of {!HASHED_VALUE.polyeq} for details on this. *) module HeterogeneousHashedValue : HETEROGENEOUS_HASHED_VALUE with type ('k, 'm) t = 'm -(** Generic implementation of {!Sigs.HETEROGENEOUS_HASHED_VALUE}. +(** Generic implementation of {!HETEROGENEOUS_HASHED_VALUE}. Uses {{: https://ocaml.org/api/Hashtbl.html#VALhash}[Hashtbl.hash]} for hashing and physical equality for equality. Note that this may lead to maps of different types having the same identifier ({!MakeHashconsedHeterogeneousMap.to_int}), see the documentation of - {!Sigs.HASHED_VALUE.polyeq} for details on this. *) + {!HASHED_VALUE.polyeq} for details on this. *) (**/**) (** For local library use only *) module HeterogeneousKeyFromKey(Key: KEY): HETEROGENEOUS_KEY with type 'a t = Key.t -(** Create a {!Sigs.HETEROGENEOUS_KEY} from a non-polymorphic {!Sigs.KEY} *) +(** Create a {!HETEROGENEOUS_KEY} from a non-polymorphic {!KEY} *) module HeterogeneousHashedValueFromHashedValue(Value: HASHED_VALUE) : HETEROGENEOUS_HASHED_VALUE with type ('a, 'map) t = ('a, 'map Value.t) snd -(** Create a {!Sigs.HETEROGENEOUS_HASHED_VALUE} from a {!Sigs.HASHED_VALUE} *) +(** Create a {!HETEROGENEOUS_HASHED_VALUE} from a {!HASHED_VALUE} *) (**/**) diff --git a/src/sigs.ml b/src/sigs.ml index 74aa18a..0fded08 100644 --- a/src/sigs.ml +++ b/src/sigs.ml @@ -53,7 +53,7 @@ module type NODE = sig (** The empty map *) val leaf : 'key key -> ('key, 'map) value -> 'map t - (** A singleton leaf, similar to {!Sigs.BASE_MAP.singleton} *) + (** A singleton leaf, similar to {!BASE_MAP.singleton} *) val branch : prefix:intkey -> @@ -114,7 +114,7 @@ module type NODE_WITH_ID = sig end (** Hash-consed nodes also associate a unique number to each node, - Unlike {!Sigs.NODE_WITH_ID}, they also check before instanciating the node whether + Unlike {!NODE_WITH_ID}, they also check before instanciating the node whether a similar node already exists. This results in slightly slower constructors (they perform an extra hash-table lookup), but allows for constant time equality and comparison. @@ -127,24 +127,24 @@ module type HASH_CONSED_NODE = sig val to_int : 'a t -> int (** Returns a unique number for each map, the {{!hash_consed}hash-consed} identifier of the map. - Unlike {!Sigs.NODE_WITH_ID.to_int}, hash-consing ensures that maps - which contain the same keys (compared by {!Sigs.KEY.to_int}) and values (compared - by {!Sigs.HASHED_VALUE.polyeq}) will always be physically equal + Unlike {!NODE_WITH_ID.to_int}, hash-consing ensures that maps + which contain the same keys (compared by {!KEY.to_int}) and values (compared + by {!HASHED_VALUE.polyeq}) will always be physically equal and have the same identifier. Maps with the same identifier are also physically equal: [to_int m1 = to_int m2] implies [m1 == m2]. - Note that when using physical equality as {!Sigs.HASHED_VALUE.polyeq}, some + Note that when using physical equality as {!HASHED_VALUE.polyeq}, some maps of different types [a t] and [b t] may be given the same identifier. - See the end of the documentation of {!Sigs.HASHED_VALUE.polyeq} for details. *) + See the end of the documentation of {!HASHED_VALUE.polyeq} for details. *) val equal : 'a t -> 'a t -> bool (** Constant time equality using the {{!hash_consed}hash-consed} nodes identifiers. This is equivalent to physical equality. Two nodes are equal if their trees contain the same bindings, - where keys are compared by {!Sigs.KEY.to_int} and values are compared by - {!Sigs.HASHED_VALUE.polyeq}. *) + where keys are compared by {!KEY.to_int} and values are compared by + {!HASHED_VALUE.polyeq}. *) val compare : 'a t -> 'a t -> int (** Constant time comparison using the {{!hash_consed}hash-consed} node identifiers. @@ -164,12 +164,12 @@ end of ['a key] to [('a,'b) values]. All maps and set are a variation of this type, sometimes with a simplified interface. - - {!Sigs.HETEROGENEOUS_MAP} is just a {!Sigs.BASE_MAP} with a functor {!Sigs.HETEROGENEOUS_MAP.WithForeign} + - {!HETEROGENEOUS_MAP} is just a {!BASE_MAP} with a functor {!HETEROGENEOUS_MAP.WithForeign} for building operations that operate on two maps of different base types; - - {!Sigs.MAP} specializes the interface for non-generic keys ([key] instead of ['a key]); - - {!Sigs.HETEROGENEOUS_SET} specializes {!Sigs.BASE_MAP} for sets ([('a,'b) value = unit]) and + - {!MAP} specializes the interface for non-generic keys ([key] instead of ['a key]); + - {!HETEROGENEOUS_SET} specializes {!BASE_MAP} for sets ([('a,'b) value = unit]) and removes the value argument from most operations; - - {!Sigs.SET} specializes {!Sigs.HETEROGENEOUS_SET} further by making elements (keys) + - {!SET} specializes {!HETEROGENEOUS_SET} further by making elements (keys) non-generic ([elt] instead of ['a elt]). *) module type BASE_MAP = sig include NODE (** @closed *) @@ -182,12 +182,12 @@ module type BASE_MAP = sig val unsigned_min_binding : 'a t -> 'a key_value_pair (** [unsigned_min_binding m] is minimal binding [KeyValue(k,v)] of the map, - using the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int}. + using the {{!unsigned_lt}unsigned order} on {!KEY.to_int}. @raises Not_found if the map is empty *) val unsigned_max_binding : 'a t -> 'a key_value_pair (** [unsigned_max_binding m] is maximal binding [KeyValue(k,v)] of the map, - using the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int}. + using the {{!unsigned_lt}unsigned order} on {!KEY.to_int}. @raises Not_found if the map is empty *) val singleton : 'a key -> ('a, 'b) value -> 'b t @@ -217,13 +217,13 @@ module type BASE_MAP = sig val pop_unsigned_minimum: 'map t -> ('map key_value_pair * 'map t) option (** [pop_unsigned_minimum m] returns [None] if [is_empty m], or [Some(key,value,m')] where [(key,value) = unsigned_min_binding m] and [m' = remove m key]. - Uses the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int}. + Uses the {{!unsigned_lt}unsigned order} on {!KEY.to_int}. O(log(n)) complexity. *) val pop_unsigned_maximum: 'map t -> ('map key_value_pair * 'map t) option (** [pop_unsigned_maximum m] returns [None] if [is_empty m], or [Some(key,value,m')] where [(key,value) = unsigned_max_binding m] and [m' = remove m key]. - Uses the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int}. + Uses the {{!unsigned_lt}unsigned order} on {!KEY.to_int}. O(log(n)) complexity. *) val insert: 'a key -> (('a,'map) value option -> ('a,'map) value) -> 'map t -> 'map t @@ -255,18 +255,18 @@ module type BASE_MAP = sig - value associated to [key] (if present) - submap of [map] whose keys are bigger than [key] - Where the order is given by the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int}. *) + Where the order is given by the {{!unsigned_lt}unsigned order} on {!KEY.to_int}. *) type 'map polyiter = { f : 'a. 'a key -> ('a, 'map) value -> unit; } [@@unboxed] val iter : 'map polyiter -> 'map t -> unit (** [iter f m] calls [f.f] on all bindings of [m], - in the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int} *) + in the {{!unsigned_lt}unsigned order} on {!KEY.to_int} *) type ('acc,'map) polyfold = { f: 'a. 'a key -> ('a,'map) value -> 'acc -> 'acc } [@@unboxed] val fold : ('acc,'map) polyfold -> 'map t -> 'acc -> 'acc (** [fold f m acc] returns [f.f key_n value_n (... (f.f key_1 value_1 acc))] where [(key_1, value_1) ... (key_n, value_n)] are the bindings of [m], in - the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int}. *) + the {{!unsigned_lt}unsigned order} on {!KEY.to_int}. *) type ('acc,'map) polyfold2 = { f: 'a. 'a key -> ('a,'map) value -> ('a,'map) value -> 'acc -> 'acc } [@@unboxed] val fold_on_nonequal_inter : ('acc,'map) polyfold2 -> 'map t -> 'map t -> 'acc -> 'acc @@ -274,7 +274,7 @@ module type BASE_MAP = sig [f.f key_n value1_n value2n (... (f.f key_1 value1_1 value2_1 acc))] where [(key_1, value1_1, value2_1) ... (key_n, value1_n, value2_n)] are the bindings that exist in both maps ([m1 ∩ m2]) whose values are physically different. - Calls to [f.f] are performed in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + Calls to [f.f] are performed in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) type ('acc,'map) polyfold2_union = { f: 'a. 'a key -> ('a,'map) value option -> ('a,'map) value option -> 'acc -> 'acc } [@@unboxed] @@ -284,13 +284,13 @@ module type BASE_MAP = sig [(key_1, value1_1, value2_1) ... (key_n, value1_n, value2_n)] are the bindings that exists in either map ([m1 ∪ m2]) whose values are physically different. - Calls to [f.f] are performed in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + Calls to [f.f] are performed in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) type 'map polypredicate = { f: 'a. 'a key -> ('a,'map) value -> bool; } [@@unboxed] val filter : 'map polypredicate -> 'map t -> 'map t (** [filter f m] returns the submap of [m] containing the bindings [k->v] such that [f.f k v = true]. - [f.f] is called in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int} *) + [f.f] is called in the {{!unsigned_lt}unsigned order} of {!KEY.to_int} *) val for_all : 'map polypredicate -> 'map t -> bool (** [for_all f m] checks that [f] holds on all bindings of [m]. @@ -306,14 +306,14 @@ module type BASE_MAP = sig val map : ('map,'map) polymap -> 'map t -> 'map t val map_no_share : ('map1,'map2) polymap -> 'map1 t -> 'map2 t (** [map f m] and [map_no_share f m] replace all bindings [(k,v)] by [(k, f.f v)]. - Bindings are examined in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + Bindings are examined in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) type ('map1,'map2) polymapi = { f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value; } [@@unboxed] val mapi : ('map,'map) polymapi -> 'map t -> 'map t val mapi_no_share : ('map1,'map2) polymapi -> 'map1 t -> 'map2 t (** [mapi f m] and [mapi_no_share f m] replace all bindings [(k,v)] by [(k, f.f k v)]. - Bindings are examined in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + Bindings are examined in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) type ('map1,'map2) polyfilter_map = { f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option; } [@@unboxed] @@ -322,7 +322,7 @@ module type BASE_MAP = sig (** [filter_map m f] and [filter_map_no_share m f] remove the bindings [(k,v)] for which [f.f k v] is [None], and replaces the bindings [(k,v)] for which [f.f k v] is [Some v'] by [(k,v')]. - Bindings are examined in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + Bindings are examined in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) type 'map polypretty = { f: 'a. Format.formatter -> 'a key -> ('a, 'map) value -> unit } [@@unboxed] val pretty : @@ -331,7 +331,7 @@ module type BASE_MAP = sig (** Pretty-prints a map using the given formatter. [pp_sep] is called once between each binding, it defaults to {{: https://v2.ocaml.org/api/Format.html#VALpp_print_cut}[Format.pp_print_cut]}. - Bindings are printed in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int} *) + Bindings are printed in the {{!unsigned_lt}unsigned order} of {!KEY.to_int} *) (** {1 Functions on pairs of maps} *) @@ -345,7 +345,7 @@ module type BASE_MAP = sig - for all bindings [(k, v1)] in [m1] and [(k, v2)] in [m2], [f.f k v1 v2] holds {b Assumes} [f.f] is reflexive, i.e. [f.f k v v = true] to skip calls to equal subtrees. - Calls [f.f] in ascending {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. + Calls [f.f] in ascending {{!unsigned_lt}unsigned order} of {!KEY.to_int}. Exits early if the domains mismatch or if [f.f] returns false. It is useful to implement equality on maps: @@ -361,7 +361,7 @@ module type BASE_MAP = sig ('map1,'map2) polysame_domain_for_all2 -> 'map1 t -> 'map2 t -> bool (** [nonreflexive_same_domain_for_all2 f m1 m2] is the same as {!reflexive_same_domain_for_all2}, but doesn't assume [f.f] is reflexive. - It thus calls [f.f] on every binding, in ascending {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. + It thus calls [f.f] on every binding, in ascending {{!unsigned_lt}unsigned order} of {!KEY.to_int}. Exits early if the domains mismatch or if [f.f] returns false. *) val reflexive_subset_domain_for_all2 : @@ -371,7 +371,7 @@ module type BASE_MAP = sig - for all bindings [(k, v1)] in [m1] and [(k, v2)] in [m2], [f.f k v1 v2] holds {b Assumes} [f.f] is reflexive, i.e. [f.f k v v = true] to skip calls to equal subtrees. - Calls [f.f] in ascending {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. + Calls [f.f] in ascending {{!unsigned_lt}unsigned order} of {!KEY.to_int}. Exits early if the domains mismatch. *) type ('map1, 'map2, 'map3) polyunion = { @@ -382,7 +382,7 @@ module type BASE_MAP = sig the values of keys mapped in both maps. {b Assumes} [f.f] idempotent (i.e. [f key value value == value]) - [f.f] is called in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. + [f.f] is called in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. [f.f] is never called on physically equal values. Preserves physical equality as much as possible. Complexity is O(log(n)*Delta) where Delta is the number of @@ -397,7 +397,7 @@ module type BASE_MAP = sig the values a key is mapped in both maps. {b Assumes} [f.f] idempotent (i.e. [f key value value == value]) - [f.f] is called in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. + [f.f] is called in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. [f.f] is never called on physically equal values. Preserves physical equality as much as possible. Complexity is O(log(n)*Delta) where Delta is the number of @@ -427,10 +427,10 @@ module type BASE_MAP = sig (** {1 Conversion functions} *) val to_seq : 'a t -> 'a key_value_pair Seq.t - (** [to_seq m] iterates the whole map, in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int} *) + (** [to_seq m] iterates the whole map, in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int} *) val to_rev_seq : 'a t -> 'a key_value_pair Seq.t - (** [to_rev_seq m] iterates the whole map, in decreasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int} *) + (** [to_rev_seq m] iterates the whole map, in decreasing {{!unsigned_lt}unsigned order} of {!KEY.to_int} *) val add_seq : 'a key_value_pair Seq.t -> 'a t -> 'a t (** [add_seq s m] adds all bindings of the sequence [s] to [m] in order. *) @@ -444,17 +444,17 @@ module type BASE_MAP = sig If a key is bound multiple times in [l], the latest binding is kept *) val to_list : 'a t -> 'a key_value_pair list - (** [to_list m] returns the bindings of [m] as a list, in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int} *) + (** [to_list m] returns the bindings of [m] as a list, in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int} *) end (** {2 Heterogeneous maps and sets} *) (** Maps and sets with generic keys ['a key] and values [('a,'b) value] *) module type HETEROGENEOUS_MAP = sig - (** This is the same as {!Sigs.MAP}, but with simple type [key] being replaced by type + (** This is the same as {!MAP}, but with simple type [key] being replaced by type constructor ['a key] and ['b value] being replaced by [('a,'b) value]. - The main changes from {!Sigs.MAP} are: + The main changes from {!MAP} are: - The type of {!key} is replaced by a type constructor ['k key]. Because of that, most higher-order arguments require higher-ranking polymorphism, and we provide records that allows to @@ -468,17 +468,17 @@ module type HETEROGENEOUS_MAP = sig include BASE_MAP (** @closed *) (** Operation with maps/set of different types. - [Map2] must use the same {!Sigs.KEY.to_int} function. *) + [Map2] must use the same {!KEY.to_int} function. *) module WithForeign(Map2:BASE_MAP with type 'a key = 'a key):sig type ('map1,'map2) polyinter_foreign = { f: 'a. 'a key -> ('a,'map1) value -> ('a,'map2) Map2.value -> ('a,'map1) value } [@@unboxed] val nonidempotent_inter : ('a,'b) polyinter_foreign -> 'a t -> 'b Map2.t -> 'a t - (** Like {!Sigs.BASE_MAP.idempotent_inter}. Tries to preserve physical equality on the first argument when possible. *) + (** Like {!BASE_MAP.idempotent_inter}. Tries to preserve physical equality on the first argument when possible. *) type ('map2,'map1) polyfilter_map_foreign = { f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option; } [@@unboxed] val filter_map_no_share : ('map2,'map1) polyfilter_map_foreign -> 'map2 Map2.t -> 'map1 t - (** Like {!Sigs.BASE_MAP.filter_map_no_share}, but allows to transform a foreigh map into the current one. *) + (** Like {!BASE_MAP.filter_map_no_share}, but allows to transform a foreigh map into the current one. *) type ('map1,'map2) polyupdate_multiple = { f: 'a. 'a key -> ('a,'map1) value option -> ('a,'map2) Map2.value -> ('a,'map1) value option } [@@unboxed] val update_multiple_from_foreign : 'b Map2.t -> ('a,'b) polyupdate_multiple -> 'a t -> 'a t @@ -489,7 +489,7 @@ module type HETEROGENEOUS_MAP = sig i.e. [update_multiple_from_foreign m_from f m_to] calls [f.f] on every key of [m_from], says if the corresponding value also exists in [m_to], and adds or remove the element in [m_to] depending on the value of [f.f]. - [f.f] is called in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. + [f.f] is called in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. O(size(m_from) + size(m_to)) complexity. *) type ('map1,'map2) polyupdate_multiple_inter = { f: 'a. 'a key -> ('a,'map1) value -> ('a,'map2) Map2.value -> ('a,'map1) value option } [@@unboxed] @@ -503,9 +503,9 @@ end module type HETEROGENEOUS_SET = sig (** A set containing different keys, very similar to - {!Sigs.SET}, but with simple type [elt] being replaced by type + {!SET}, but with simple type [elt] being replaced by type constructor ['a elt]. *) - (** The main changes from {!Sigs.SET} are: + (** The main changes from {!SET} are: - The type of {!elt} is replaced by a type constructor ['k elt]. Because of that, most higher-order arguments require higher-ranking polymorphism, and we provide records that allows to @@ -608,22 +608,22 @@ module type HETEROGENEOUS_SET = sig type polyiter = { f: 'a. 'a elt -> unit; } [@@unboxed] val iter: polyiter -> t -> unit - (** [iter f set] calls [f.f] on all elements of [set], in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + (** [iter f set] calls [f.f] on all elements of [set], in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) type polypredicate = { f: 'a. 'a elt -> bool; } [@@unboxed] val filter: polypredicate -> t -> t (** [filter f set] is the subset of [set] that only contains the elements that - satisfy [f.f]. [f.f] is called in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + satisfy [f.f]. [f.f] is called in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) val for_all: polypredicate -> t -> bool (** [for_all f set] is [true] if [f.f] is [true] on all elements of [set]. - Short-circuits on first [false]. [f.f] is called in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + Short-circuits on first [false]. [f.f] is called in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) type 'acc polyfold = { f: 'a. 'a elt -> 'acc -> 'acc } [@@unboxed] val fold: 'acc polyfold -> t -> 'acc -> 'acc (** [fold f set acc] returns [f.f elt_n (... (f.f elt_1 acc) ...)], where [elt_1, ..., elt_n] are the elements of [set], in increasing {{!unsigned_lt}unsigned order} of - {!Sigs.KEY.to_int} *) + {!KEY.to_int} *) type polypretty = { f: 'a. Format.formatter -> 'a elt -> unit; } [@@unboxed] val pretty : @@ -634,10 +634,10 @@ module type HETEROGENEOUS_SET = sig (** {3 Conversion functions} *) val to_seq : t -> any_elt Seq.t - (** [to_seq st] iterates the whole set, in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int} *) + (** [to_seq st] iterates the whole set, in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int} *) val to_rev_seq : t -> any_elt Seq.t - (** [to_rev_seq st] iterates the whole set, in decreasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int} *) + (** [to_rev_seq st] iterates the whole set, in decreasing {{!unsigned_lt}unsigned order} of {!KEY.to_int} *) val add_seq : any_elt Seq.t -> t -> t (** [add_seq s st] adds all elements of the sequence [s] to [st] in order. *) @@ -649,7 +649,7 @@ module type HETEROGENEOUS_SET = sig (** [of_list l] creates a new set from the elements of [l]. *) val to_list : t -> any_elt list - (** [to_list s] returns the elements of [s] as a list, in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int} *) + (** [to_list s] returns the elements of [s] as a list, in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int} *) end @@ -704,46 +704,46 @@ module type SET = sig Returns a value physically equal to [set] if [elt] is not present. *) val unsigned_min_elt: t -> elt - (** The minimal element (according to the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int}) if non empty. + (** The minimal element (according to the {{!unsigned_lt}unsigned order} on {!KEY.to_int}) if non empty. @raises Not_found *) val unsigned_max_elt: t -> elt - (** The maximal element (according to the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int}) if non empty. + (** The maximal element (according to the {{!unsigned_lt}unsigned order} on {!KEY.to_int}) if non empty. @raises Not_found *) val pop_unsigned_minimum: t -> (elt * t) option (** [pop_unsigned_minimum s] is [Some (elt, s')] where [elt = unsigned_min_elt s] and [s' = remove elt s] if [s] is non empty. - Uses the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int}. *) + Uses the {{!unsigned_lt}unsigned order} on {!KEY.to_int}. *) val pop_unsigned_maximum: t -> (elt * t) option (** [pop_unsigned_maximum s] is [Some (elt, s')] where [elt = unsigned_max_elt s] and [s' = remove elt s] if [s] is non empty. - Uses the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int}. *) + Uses the {{!unsigned_lt}unsigned order} on {!KEY.to_int}. *) (** {3 Iterators} *) val iter: (elt -> unit) -> t -> unit - (** [iter f set] calls [f] on all elements of [set], in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + (** [iter f set] calls [f] on all elements of [set], in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) val filter: (elt -> bool) -> t -> t (** [filter f set] is the subset of [set] that only contains the elements that - satisfy [f]. [f] is called in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + satisfy [f]. [f] is called in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) val for_all: (elt -> bool) -> t -> bool (** [for_all f set] is [true] if [f] is [true] on all elements of [set]. - Short-circuits on first [false]. [f] is called in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + Short-circuits on first [false]. [f] is called in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) val fold: (elt -> 'acc -> 'acc) -> t -> 'acc -> 'acc (** [fold f set acc] returns [f elt_n (... (f elt_1 acc) ...)], where [elt_1, ..., elt_n] are the elements of [set], in increasing {{!unsigned_lt}unsigned order} of - {!Sigs.KEY.to_int} *) + {!KEY.to_int} *) val split: elt -> t -> t * bool * t (** [split elt set] returns [s_lt, present, s_gt] where [s_lt] contains all elements of [set] smaller than [elt], [s_gt] all those greater than [elt], and [present] is [true] if [elt] is in [set]. - Uses the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int}.*) + Uses the {{!unsigned_lt}unsigned order} on {!KEY.to_int}.*) val pretty : ?pp_sep:(Format.formatter -> unit -> unit) -> @@ -773,10 +773,10 @@ module type SET = sig (** {3 Conversion functions} *) val to_seq : t -> elt Seq.t - (** [to_seq st] iterates the whole set, in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int} *) + (** [to_seq st] iterates the whole set, in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int} *) val to_rev_seq : t -> elt Seq.t - (** [to_rev_seq st] iterates the whole set, in decreasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int} *) + (** [to_rev_seq st] iterates the whole set, in decreasing {{!unsigned_lt}unsigned order} of {!KEY.to_int} *) val add_seq : elt Seq.t -> t -> t (** [add_seq s st] adds all elements of the sequence [s] to [st] in order. *) @@ -788,7 +788,7 @@ module type SET = sig (** [of_list l] creates a new set from the elements of [l]. *) val to_list : t -> elt list - (** [to_list s] returns the elements of [s] as a list, in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int} *) + (** [to_list s] returns the elements of [s] as a list, in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int} *) end (** The typechecker struggles with forall quantification on values if they @@ -804,7 +804,7 @@ type (_, 'b) snd = Snd of 'b [@@unboxed] (** The signature for maps with a single type for keys and values, a ['a map] binds [key] to ['a value]. - This is slightly more generic than {!Sigs.MAP}, which just binds to ['a]. + This is slightly more generic than {!MAP}, which just binds to ['a]. It is used for maps that need to restrict their value type, namely {!hash_consed}. *) module type MAP_WITH_VALUE = sig type key @@ -815,7 +815,7 @@ module type MAP_WITH_VALUE = sig type 'a value (** Type for values, this is a divergence from Stdlib's [Map], - but becomes equivalent to it when using {!Sigs.MAP}, + but becomes equivalent to it when using {!MAP}, which is just [MAP_WITH_VALUE with type 'a value = 'a]. On the other hand, it allows defining maps with fixed values, which is useful for hash-consing. @@ -872,12 +872,12 @@ module type MAP_WITH_VALUE = sig val pop_unsigned_minimum : 'a t -> (key * 'a value * 'a t) option (** [pop_unsigned_minimum m] returns [None] if [is_empty m], or [Some(key,value,m')] where [(key,value) = unsigned_min_binding m] and [m' = remove m key]. O(log(n)) complexity. - Uses the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int}. *) + Uses the {{!unsigned_lt}unsigned order} on {!KEY.to_int}. *) val pop_unsigned_maximum : 'a t -> (key * 'a value * 'a t) option (** [pop_unsigned_maximum m] returns [None] if [is_empty m], or [Some(key,value,m')] where [(key,value) = unsigned_max_binding m] and [m' = remove m key]. O(log(n)) complexity. - Uses the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int}. *) + Uses the {{!unsigned_lt}unsigned order} on {!KEY.to_int}. *) val insert : key -> ('a value option -> 'a value) -> 'a t -> 'a t (** [insert key f map] modifies or insert an element of the map; [f] @@ -908,13 +908,13 @@ module type MAP_WITH_VALUE = sig - value associated to [key] (if present) - submap of [map] whose keys are bigger than [key] - Uses the {{!unsigned_lt}unsigned order} on {!Sigs.KEY.to_int}. *) + Uses the {{!unsigned_lt}unsigned order} on {!KEY.to_int}. *) val iter : (key -> 'a value -> unit) -> 'a t -> unit - (** Iterate on each [(key,value)] pair of the map, in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + (** Iterate on each [(key,value)] pair of the map, in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) val fold : (key -> 'a value -> 'acc -> 'acc) -> 'a t -> 'acc -> 'acc - (** Fold on each [(key,value)] pair of the map, in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + (** Fold on each [(key,value)] pair of the map, in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) val fold_on_nonequal_inter : (key -> 'a value -> 'a value -> 'acc -> 'acc) -> 'a t -> 'a t -> 'acc -> 'acc @@ -922,7 +922,7 @@ module type MAP_WITH_VALUE = sig [f key_n value1_n value2n (... (f key_1 value1_1 value2_1 acc))] where [(key_1, value1_1, value2_1) ... (key_n, value1_n, value2_n)] are the bindings that exist in both maps ([m1 ∩ m2]) whose values are physically different. - Calls to [f] are performed in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + Calls to [f] are performed in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) val fold_on_nonequal_union: (key -> 'a value option -> 'a value option -> 'acc -> 'acc) -> 'a t -> 'a t -> 'acc -> 'acc @@ -931,15 +931,15 @@ module type MAP_WITH_VALUE = sig [(key_1, value1_1, value2_1) ... (key_n, value1_n, value2_n)] are the bindings that exists in either map ([m1 ∪ m2]) whose values are physically different. - Calls to [f.f] are performed in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + Calls to [f.f] are performed in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) val filter : (key -> 'a value -> bool) -> 'a t -> 'a t (** Returns the submap containing only the key->value pairs satisfying the - given predicate. [f] is called in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + given predicate. [f] is called in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) val for_all : (key -> 'a value -> bool) -> 'a t -> bool (** Returns true if the predicate holds on all map bindings. Short-circuiting. - [f] is called in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + [f] is called in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) (** In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while @@ -953,12 +953,12 @@ module type MAP_WITH_VALUE = sig value is physically the same (i.e. [f key value == value] for all the keys in the subtree) are guaranteed to be physically equal to the original subtree. O(n) complexity. - [f] is called in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + [f] is called in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) val map_no_share : ('a value -> 'b value) -> 'a t -> 'b t (** [map_no_share f m] returns a map where the [value] bound to each [key] is replaced by [f value]. O(n) complexity. - [f] is called in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + [f] is called in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) val mapi : (key -> 'a value -> 'a value) -> 'a t -> 'a t (** [mapi f m] returns a map where the [value] bound to each [key] is @@ -966,12 +966,12 @@ module type MAP_WITH_VALUE = sig value is physically the same (i.e. [f key value == value] for all the keys in the subtree) are guaranteed to be physically equal to the original subtree. O(n) complexity. - [f] is called in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + [f] is called in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) val mapi_no_share : (key -> 'a value -> 'b value) -> 'a t -> 'b t (** [mapi_no_share f m] returns a map where the [value] bound to each [key] is replaced by [f key value]. O(n) complexity. - [f] is called in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + [f] is called in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) val filter_map : (key -> 'a value -> 'a value option) -> 'a t -> 'a t (** [filter_map m f] returns a map where the [value] bound to each @@ -981,14 +981,14 @@ module type MAP_WITH_VALUE = sig (i.e. [f key value = Some v] with [value == v] for all the keys in the subtree) are guaranteed to be physically equal to the original subtree. O(n) complexity. - [f] is called in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + [f] is called in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) val filter_map_no_share : (key -> 'a value -> 'b value option) -> 'a t -> 'b t (** [filter_map m f] returns a map where the [value] bound to each [key] is removed (if [f key value] returns [None]), or is replaced by [v] ((if [f key value] returns [Some v]). O(n) complexity. - [f] is called in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. *) + [f] is called in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int}. *) (** {3 Operations on pairs of maps} *) @@ -1043,7 +1043,7 @@ module type MAP_WITH_VALUE = sig preserve physical equality of the subtreess in that case. The complexity is O(log(n)*Delta) where Delta is the number of different keys between [map1] and [map2]. - [f] is called in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. + [f] is called in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int}. [f] is never called on physically equal values. *) val idempotent_inter : (key -> 'a value -> 'a value -> 'a value) -> 'a t -> 'a t -> 'a t @@ -1055,7 +1055,7 @@ module type MAP_WITH_VALUE = sig preserve physical equality of the subtrees in that case. The complexity is O(log(n)*Delta) where Delta is the number of different keys between [map1] and [map2]. - [f] is called in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}!. + [f] is called in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int}!. [f] is never called on physically equal values. *) val nonidempotent_inter_no_share : (key -> 'a value -> 'b value -> 'c value) -> 'a t -> 'b t -> 'c t @@ -1065,7 +1065,7 @@ module type MAP_WITH_VALUE = sig need to be idempotent, which imply that we have to visit physically equal subtrees of [map1] and [map2]. The complexity is O(log(n)*min(|map1|,|map2|)). - [f] is called in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. + [f] is called in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int}. [f] is called on every shared binding. *) val idempotent_inter_filter : (key -> 'a value -> 'a value -> 'a value option) -> 'a t -> 'a t -> 'a t @@ -1085,7 +1085,7 @@ module type MAP_WITH_VALUE = sig (** [disjoint a b] is [true] if and only if [a] and [b] have disjoint domains. *) (** Combination with other kinds of maps. - [Map2] must use the same {!Sigs.KEY.to_int} function. *) + [Map2] must use the same {!KEY.to_int} function. *) module WithForeign(Map2 : BASE_MAP with type _ key = key):sig type ('b,'c) polyfilter_map_foreign = { f: 'a. key -> ('a,'b) Map2.value -> 'c value option } [@@unboxed] @@ -1107,7 +1107,7 @@ module type MAP_WITH_VALUE = sig i.e. [update_multiple_from_foreign m_from f m_to] calls [f.f] on every key of [m_from], says if the corresponding value also exists in [m_to], and adds or remove the element in [m_to] depending on the value of [f.f]. - [f.f] is called in the {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int}. + [f.f] is called in the {{!unsigned_lt}unsigned order} of {!KEY.to_int}. O(size(m_from) + size(m_to)) complexity. *) @@ -1129,10 +1129,10 @@ module type MAP_WITH_VALUE = sig (** {3 Conversion functions} *) val to_seq : 'a t -> (key * 'a value) Seq.t - (** [to_seq m] iterates the whole map, in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int} *) + (** [to_seq m] iterates the whole map, in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int} *) val to_rev_seq : 'a t -> (key * 'a value) Seq.t - (** [to_rev_seq m] iterates the whole map, in decreasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int} *) + (** [to_rev_seq m] iterates the whole map, in decreasing {{!unsigned_lt}unsigned order} of {!KEY.to_int} *) val add_seq : (key * 'a value) Seq.t -> 'a t -> 'a t (** [add_seq s m] adds all bindings of the sequence [s] to [m] in order. *) @@ -1147,7 +1147,7 @@ module type MAP_WITH_VALUE = sig val to_list : 'a t -> (key * 'a value) list (** [to_list m] returns the bindings of [m] as a list, - in increasing {{!unsigned_lt}unsigned order} of {!Sigs.KEY.to_int} *) + in increasing {{!unsigned_lt}unsigned order} of {!KEY.to_int} *) end (** The signature for maps with a single type for keys and values, @@ -1163,21 +1163,21 @@ module type HASH_CONSED_OPERATIONS = sig val to_int : 'a t -> int (** Returns the {{!hash_consed}hash-consed} id of the map. - Unlike {!Sigs.NODE_WITH_ID.to_int}, hash-consing ensures that maps - which contain the same keys (compared by {!Sigs.KEY.to_int}) and values (compared - by {!Sigs.HASHED_VALUE.polyeq}) will always be physically equal + Unlike {!NODE_WITH_ID.to_int}, hash-consing ensures that maps + which contain the same keys (compared by {!KEY.to_int}) and values (compared + by {!HASHED_VALUE.polyeq}) will always be physically equal and have the same identifier. - Note that when using physical equality as {!Sigs.HASHED_VALUE.polyeq}, some + Note that when using physical equality as {!HASHED_VALUE.polyeq}, some maps of different types [a t] and [b t] may be given the same identifier. - See the end of the documentation of {!Sigs.HASHED_VALUE.polyeq} for details. *) + See the end of the documentation of {!HASHED_VALUE.polyeq} for details. *) val equal : 'a t -> 'a t -> bool (** Constant time equality using the {{!hash_consed}hash-consed} nodes identifiers. This is equivalent to physical equality. Two nodes are equal if their trees contain the same bindings, - where keys are compared by {!Sigs.KEY.to_int} and values are compared by - {!Sigs.HASHED_VALUE.polyeq}. *) + where keys are compared by {!KEY.to_int} and values are compared by + {!HASHED_VALUE.polyeq}. *) val compare : 'a t -> 'a t -> int (** Constant time comparison using the {{!hash_consed}hash-consed} node identifiers. @@ -1214,7 +1214,7 @@ module type KEY = sig Note that since Patricia Trees use {{!unsigned_lt}unsigned order}, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like - {{!Sigs.BASE_MAP.unsigned_max_binding}[unsigned_max_binding]} and {{!Sigs.BASE_MAP.pop_unsigned_maximum}[pop_unsigned_maximum]}. *) + {{!BASE_MAP.unsigned_max_binding}[unsigned_max_binding]} and {{!BASE_MAP.pop_unsigned_maximum}[pop_unsigned_maximum]}. *) val to_int: t -> int end @@ -1247,7 +1247,7 @@ module type HETEROGENEOUS_KEY = sig Note that since Patricia Trees use {{!unsigned_lt}unsigned order}, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like - {{!Sigs.BASE_MAP.unsigned_max_binding}[unsigned_max_binding]} and {{!Sigs.BASE_MAP.pop_unsigned_maximum}[pop_unsigned_maximum]}. *) + {{!BASE_MAP.unsigned_max_binding}[unsigned_max_binding]} and {{!BASE_MAP.pop_unsigned_maximum}[pop_unsigned_maximum]}. *) val polyeq : 'a t -> 'b t -> ('a, 'b) cmp (** Polymorphic equality function used to compare our keys. @@ -1264,7 +1264,7 @@ end This is the case in {!MakeMap}. However, for maps like {!hash_consed}, it can be useful to restrict the type of values in order to implement [hash] and [polyeq] functions on values. - See the {!Sigs.HASHED_VALUE} module type for more details. + See the {!HASHED_VALUE} module type for more details. @since 0.10.0 *) module type VALUE = sig @@ -1283,7 +1283,7 @@ module type HETEROGENEOUS_VALUE = sig Can be mutable if desired, unless it is being used in {!hash_consed}. *) end -(** {!Sigs.VALUE} parameter for {!hash_consed}, as hash-consing requires hashing and comparing values. +(** {!VALUE} parameter for {!hash_consed}, as hash-consing requires hashing and comparing values. This is the parameter type for homogeneous maps, used in {!MakeHashconsedMap}. A default implementation is provided in {!HashedValue}, using @@ -1295,7 +1295,7 @@ module type HASHED_VALUE = sig type 'a t (** The type of values for a hash-consed maps. - Unlike {!Sigs.VALUE.t}, {b hash-consed values should be immutable}. + Unlike {!VALUE.t}, {b hash-consed values should be immutable}. Or, if they do mutate, they must not change their {!hash} value, and still be equal to the same values via {!polyeq} *) @@ -1391,7 +1391,7 @@ end (** In order to build {!hash_consed}, we need to be able to hash and compare values. - This is the heterogeneous version of {!Sigs.HASHED_VALUE}, used to specify a value + This is the heterogeneous version of {!HASHED_VALUE}, used to specify a value for heterogeneous maps (in {!MakeHashconsedHeterogeneousMap}). A default implementation is provided in {!HeterogeneousHashedValue}, using {{: https://ocaml.org/api/Hashtbl.html#VALhash}[Hashtbl.hash]} @@ -1402,7 +1402,7 @@ module type HETEROGENEOUS_HASHED_VALUE = sig type ('key, 'map) t (** The type of values for a hash-consed maps. - Unlike {!Sigs.HETEROGENEOUS_VALUE.t}, {b hash-consed values should be immutable}. + Unlike {!HETEROGENEOUS_VALUE.t}, {b hash-consed values should be immutable}. Or, if they do mutate, they must not change their {!hash} value, and still be equal to the same values via {!polyeq} *) @@ -1453,5 +1453,5 @@ module type HETEROGENEOUS_HASHED_VALUE = sig This is the implementation used in {!HeterogeneousHashedValue}. Note however that using this function can lead to {b identifiers no longer being unique across - types}. See {!Sigs.HASHED_VALUE.polyeq} for more information on this.}} *) + types}. See {!HASHED_VALUE.polyeq} for more information on this.}} *) end