From 03f6bca3c1215e25e46841b2ca5ef2759b59fa51 Mon Sep 17 00:00:00 2001 From: dlesbre Date: Thu, 23 May 2024 13:56:48 +0000 Subject: [PATCH] Deploy 2845ec8089f576112c82d12f72feac184284dfb8 --- .../HashconsedNode/argument-1-Key/index.html | 4 + .../argument-2-Value/index.html | 13 +++ .../PatriciaTree/HashconsedNode/index.html | 11 ++ .../argument-1-Key/index.html | 4 + .../PatriciaTree/HashconsedSetNode/index.html | 9 ++ v0.10.0/PatriciaTree/HashedValue/index.html | 29 +++++ .../HeterogeneousHashedValue/index.html | 13 +++ .../PatriciaTree/HomogeneousValue/index.html | 4 + .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../WithForeign/index.html | 28 +++++ .../argument-1-Key/index.html | 4 + .../argument-2-Value/index.html | 4 + .../argument-3-Node/index.html | 9 ++ .../MakeCustomHeterogeneousMap/index.html | 78 ++++++++++++++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../BaseMap/WithForeign/index.html | 28 +++++ .../BaseMap/index.html | 75 +++++++++++++ .../argument-1-Key/index.html | 4 + .../argument-2-NODE/index.html | 9 ++ .../MakeCustomHeterogeneousSet/index.html | 13 +++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../BaseMap/WithForeign/index.html | 28 +++++ .../MakeCustomMap/BaseMap/index.html | 75 +++++++++++++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../MakeCustomMap/WithForeign/index.html | 19 ++++ .../MakeCustomMap/argument-1-Key/index.html | 4 + .../MakeCustomMap/argument-2-Value/index.html | 4 + .../MakeCustomMap/argument-3-Node/index.html | 9 ++ v0.10.0/PatriciaTree/MakeCustomMap/index.html | 60 +++++++++++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../BaseMap/WithForeign/index.html | 28 +++++ .../MakeCustomSet/BaseMap/index.html | 75 +++++++++++++ .../MakeCustomSet/argument-1-Key/index.html | 4 + .../MakeCustomSet/argument-2-Node/index.html | 9 ++ v0.10.0/PatriciaTree/MakeCustomSet/index.html | 13 +++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../WithForeign/index.html | 28 +++++ .../argument-1-Key/index.html | 4 + .../argument-2-Value/index.html | 13 +++ .../MakeHashconsedHeterogeneousMap/index.html | 75 +++++++++++++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../BaseMap/WithForeign/index.html | 28 +++++ .../BaseMap/index.html | 69 ++++++++++++ .../argument-1-Key/index.html | 4 + .../MakeHashconsedHeterogeneousSet/index.html | 10 ++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../BaseMap/WithForeign/index.html | 28 +++++ .../MakeHashconsedMap/BaseMap/index.html | 75 +++++++++++++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../MakeHashconsedMap/WithForeign/index.html | 19 ++++ .../argument-1-Key/index.html | 4 + .../argument-2-Value/index.html | 29 +++++ .../PatriciaTree/MakeHashconsedMap/index.html | 57 ++++++++++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../BaseMap/WithForeign/index.html | 28 +++++ .../MakeHashconsedSet/BaseMap/index.html | 69 ++++++++++++ .../argument-1-Key/index.html | 4 + .../PatriciaTree/MakeHashconsedSet/index.html | 10 ++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../WithForeign/index.html | 28 +++++ .../argument-1-Key/index.html | 4 + .../argument-2-Value/index.html | 4 + .../MakeHeterogeneousMap/index.html | 73 +++++++++++++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../BaseMap/WithForeign/index.html | 28 +++++ .../MakeHeterogeneousSet/BaseMap/index.html | 69 ++++++++++++ .../argument-1-Key/index.html | 4 + .../MakeHeterogeneousSet/index.html | 10 ++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../MakeMap/BaseMap/WithForeign/index.html | 28 +++++ .../PatriciaTree/MakeMap/BaseMap/index.html | 75 +++++++++++++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../MakeMap/WithForeign/index.html | 19 ++++ .../MakeMap/argument-1-Key/index.html | 4 + v0.10.0/PatriciaTree/MakeMap/index.html | 57 ++++++++++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../MakeSet/BaseMap/WithForeign/index.html | 28 +++++ .../PatriciaTree/MakeSet/BaseMap/index.html | 69 ++++++++++++ .../MakeSet/argument-1-Key/index.html | 4 + v0.10.0/PatriciaTree/MakeSet/index.html | 10 ++ .../NodeWithId/argument-1-Key/index.html | 4 + .../NodeWithId/argument-2-Value/index.html | 4 + v0.10.0/PatriciaTree/NodeWithId/index.html | 11 ++ .../SetNode/argument-1-Key/index.html | 4 + v0.10.0/PatriciaTree/SetNode/index.html | 9 ++ .../SimpleNode/argument-1-Key/index.html | 4 + .../SimpleNode/argument-2-Value/index.html | 4 + v0.10.0/PatriciaTree/SimpleNode/index.html | 9 ++ v0.10.0/PatriciaTree/Value/index.html | 4 + .../WeakNode/argument-1-Key/index.html | 4 + .../WeakNode/argument-2-Value/index.html | 4 + v0.10.0/PatriciaTree/WeakNode/index.html | 9 ++ .../WeakSetNode/argument-1-Key/index.html | 4 + v0.10.0/PatriciaTree/WeakSetNode/index.html | 9 ++ .../WrappedHomogeneousValue/index.html | 4 + v0.10.0/PatriciaTree/index.html | 101 ++++++++++++++++++ .../module-type-BASE_MAP/index.html | 69 ++++++++++++ .../module-type-HASHED_VALUE/index.html | 29 +++++ .../module-type-HASH_CONSED_NODE/index.html | 9 ++ .../index.html | 13 +++ .../module-type-HETEROGENEOUS_KEY/index.html | 4 + .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../WithForeign/index.html | 28 +++++ .../module-type-HETEROGENEOUS_MAP/index.html | 69 ++++++++++++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../BaseMap/WithForeign/index.html | 28 +++++ .../BaseMap/index.html | 69 ++++++++++++ .../module-type-HETEROGENEOUS_SET/index.html | 10 ++ .../index.html | 4 + .../PatriciaTree/module-type-KEY/index.html | 4 + .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../BaseMap/WithForeign/index.html | 28 +++++ .../module-type-MAP/BaseMap/index.html | 75 +++++++++++++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../module-type-MAP/WithForeign/index.html | 19 ++++ .../PatriciaTree/module-type-MAP/index.html | 57 ++++++++++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../BaseMap/WithForeign/index.html | 28 +++++ .../BaseMap/index.html | 75 +++++++++++++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../WithForeign/index.html | 19 ++++ .../module-type-MAP_WITH_VALUE/index.html | 57 ++++++++++ .../PatriciaTree/module-type-NODE/index.html | 9 ++ .../module-type-NODE_WITH_ID/index.html | 9 ++ .../WithForeign/argument-1-Map2/index.html | 69 ++++++++++++ .../BaseMap/WithForeign/index.html | 28 +++++ .../module-type-SET/BaseMap/index.html | 69 ++++++++++++ .../PatriciaTree/module-type-SET/index.html | 10 ++ .../PatriciaTree/module-type-VALUE/index.html | 4 + v0.10.0/db.js | 1 + v0.10.0/index.html | 97 +++++++++++++++++ 131 files changed, 4362 insertions(+) create mode 100644 v0.10.0/PatriciaTree/HashconsedNode/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/HashconsedNode/argument-2-Value/index.html create mode 100644 v0.10.0/PatriciaTree/HashconsedNode/index.html create mode 100644 v0.10.0/PatriciaTree/HashconsedSetNode/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/HashconsedSetNode/index.html create mode 100644 v0.10.0/PatriciaTree/HashedValue/index.html create mode 100644 v0.10.0/PatriciaTree/HeterogeneousHashedValue/index.html create mode 100644 v0.10.0/PatriciaTree/HomogeneousValue/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/argument-2-Value/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/argument-3-Node/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/BaseMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/BaseMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/BaseMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/argument-2-NODE/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomMap/BaseMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomMap/BaseMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomMap/BaseMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomMap/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomMap/argument-2-Value/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomMap/argument-3-Node/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomSet/BaseMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomSet/BaseMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomSet/BaseMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomSet/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomSet/argument-2-Node/index.html create mode 100644 v0.10.0/PatriciaTree/MakeCustomSet/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/argument-2-Value/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/BaseMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/BaseMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/BaseMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedMap/BaseMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedMap/BaseMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedMap/BaseMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedMap/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedMap/argument-2-Value/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedSet/BaseMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedSet/BaseMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedSet/BaseMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedSet/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHashconsedSet/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHeterogeneousMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHeterogeneousMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHeterogeneousMap/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHeterogeneousMap/argument-2-Value/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHeterogeneousMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHeterogeneousSet/BaseMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHeterogeneousSet/BaseMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHeterogeneousSet/BaseMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHeterogeneousSet/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/MakeHeterogeneousSet/index.html create mode 100644 v0.10.0/PatriciaTree/MakeMap/BaseMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeMap/BaseMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeMap/BaseMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeMap/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/MakeMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeSet/BaseMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/MakeSet/BaseMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/MakeSet/BaseMap/index.html create mode 100644 v0.10.0/PatriciaTree/MakeSet/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/MakeSet/index.html create mode 100644 v0.10.0/PatriciaTree/NodeWithId/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/NodeWithId/argument-2-Value/index.html create mode 100644 v0.10.0/PatriciaTree/NodeWithId/index.html create mode 100644 v0.10.0/PatriciaTree/SetNode/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/SetNode/index.html create mode 100644 v0.10.0/PatriciaTree/SimpleNode/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/SimpleNode/argument-2-Value/index.html create mode 100644 v0.10.0/PatriciaTree/SimpleNode/index.html create mode 100644 v0.10.0/PatriciaTree/Value/index.html create mode 100644 v0.10.0/PatriciaTree/WeakNode/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/WeakNode/argument-2-Value/index.html create mode 100644 v0.10.0/PatriciaTree/WeakNode/index.html create mode 100644 v0.10.0/PatriciaTree/WeakSetNode/argument-1-Key/index.html create mode 100644 v0.10.0/PatriciaTree/WeakSetNode/index.html create mode 100644 v0.10.0/PatriciaTree/WrappedHomogeneousValue/index.html create mode 100644 v0.10.0/PatriciaTree/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-BASE_MAP/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-HASHED_VALUE/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-HASH_CONSED_NODE/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_HASHED_VALUE/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_KEY/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_MAP/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_MAP/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_MAP/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/BaseMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/BaseMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/BaseMap/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_VALUE/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-KEY/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-MAP/BaseMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-MAP/BaseMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-MAP/BaseMap/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-MAP/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-MAP/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-MAP/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/BaseMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/BaseMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/BaseMap/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-NODE/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-NODE_WITH_ID/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-SET/BaseMap/WithForeign/argument-1-Map2/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-SET/BaseMap/WithForeign/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-SET/BaseMap/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-SET/index.html create mode 100644 v0.10.0/PatriciaTree/module-type-VALUE/index.html create mode 100644 v0.10.0/db.js create mode 100644 v0.10.0/index.html diff --git a/v0.10.0/PatriciaTree/HashconsedNode/argument-1-Key/index.html b/v0.10.0/PatriciaTree/HashconsedNode/argument-1-Key/index.html new file mode 100644 index 0000000..4868734 --- /dev/null +++ b/v0.10.0/PatriciaTree/HashconsedNode/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.HashconsedNode.Key)

Parameter HashconsedNode.Key

type 'key t

The type of generic/heterogeneous keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : 'key t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

val polyeq : 'a t -> 'b t -> ('a, 'b) cmp

Polymorphic equality function used to compare our keys. It should satisfy (to_int a) = (to_int b) ==> polyeq a b = Eq, and be fast.

diff --git a/v0.10.0/PatriciaTree/HashconsedNode/argument-2-Value/index.html b/v0.10.0/PatriciaTree/HashconsedNode/argument-2-Value/index.html new file mode 100644 index 0000000..23c16d8 --- /dev/null +++ b/v0.10.0/PatriciaTree/HashconsedNode/argument-2-Value/index.html @@ -0,0 +1,13 @@ + +Value (patricia-tree.PatriciaTree.HashconsedNode.Value)

Parameter HashconsedNode.Value

type ('key, 'map) t

The type of values for a hash-consed maps.

Unlike HETEROGENEOUS_VALUE.t, 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

val hash : ('key, 'map) t -> int

hash v should return an integer hash for the value v. It is used for hash-consing.

Hashing should be fast, avoid mapping too many values to the same integer and compatible with polyeq (equal values must have the same hash: polyeq v1 v2 = true ==> hash v1 = hash v2).

val polyeq : ('key, 'map_a) t -> ('key, 'map_b) t -> bool

Polymorphic equality on values.

WARNING: if polyeq a b is true, then casting b to the type of a (and a to the type of b) must be type-safe. Eg. if a : (k, t1) t and b : (k, t2) t yield polyeq a b = true, then let a' : (k,t2) t = Obj.magic a and let b' : (k,t1) t = Obj.magic b must be safe.

Examples of safe implementations include:

  • Having a type ('key, 'map) t which doesn't depend on 'map (i can depend on 'key), in which case casting form ('key, 'a) t to ('key, 'b) t is always safe:

    type ('k, _) t = 'k list
    +let cast : type a b. ('k, a) t -> ('k, b) t = fun x -> x
    +let polyeq : type a b. ('k, a) t -> ('k, b) t -> bool = fun x y -> x = y
  • Using a GADT type and examining its constructors to only return true when the constructors are equal:

    type (_, _) t =
    +    | T_Int : int -> (unit, int) t
    +    | T_Bool : bool -> (unit, bool) t
    +let polyeq : type k a b. (k, a) t -> (k, b) t -> bool = fun x y ->
    +    match x, y with
    +    | T_Int i, T_Int j -> i = j (* Here type a = b = int, we can return true *)
    +    | T_Bool i, T_Bool j -> i && j (* same here, but with a = b = bool *)
    +    | _ -> false (* never return true on heterogeneous cases. *)
  • Using physical equality:

    let polyeq a b = a == Obj.magic b

    While this contains an Obj.magic, it is still type safe (OCaml just compares the immediate values) and we can safely cast values from one type to the other if they satisfy this (since they are already physically equal).

    This is the implementation used in HeterogeneousHashedValue. Note however that using this function can lead to identifiers no longer being unique across types. See HASHED_VALUE.polyeq for more information on this.

diff --git a/v0.10.0/PatriciaTree/HashconsedNode/index.html b/v0.10.0/PatriciaTree/HashconsedNode/index.html new file mode 100644 index 0000000..972d3ac --- /dev/null +++ b/v0.10.0/PatriciaTree/HashconsedNode/index.html @@ -0,0 +1,11 @@ + +HashconsedNode (patricia-tree.PatriciaTree.HashconsedNode)

Module PatriciaTree.HashconsedNode

Gives a unique number to each node like NodeWithId, but also performs hash-consing. So two maps with the same bindings will always be physically equal. See Hash-consed maps and sets for more details on this.

This is a generative functor, as calling it creates a new hash-table to store the created nodes, and a reference to store the next unallocated identifier. Maps/sets from different hash-consing functors (even if these functors have the same arguments) will have different (incompatible) numbering systems and be stored in different hash-tables (thus they will never be physically equal).

Using a single HashconsedNode in multiple MakeCustomMap functors will result in all those maps being hash-consed together (stored in the same hash-table, same numbering system).

Parameters

Signature

include NODE + with type 'a key = 'a Key.t + with type ('key, 'map) value = ('key, 'map) Value.t

Types

type 'a key = 'a Key.t

The type of keys.

type ('key, 'map) value = ('key, 'map) Value.t

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

val to_int : 'a t -> int

Returns a unique number for each map, the hash-consed identifier of the map. 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 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 HASHED_VALUE.polyeq for details.

val equal : 'a t -> 'a t -> bool

Constant time equality using the 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 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 node identifiers. This order is fully arbitrary, but it is total and can be used to sort nodes. It is based on node ids which depend on the order in which the nodes where created (older nodes having smaller ids).

One useful property of this order is that child nodes will always have a smaller identifier than their parents.

diff --git a/v0.10.0/PatriciaTree/HashconsedSetNode/argument-1-Key/index.html b/v0.10.0/PatriciaTree/HashconsedSetNode/argument-1-Key/index.html new file mode 100644 index 0000000..0f68cab --- /dev/null +++ b/v0.10.0/PatriciaTree/HashconsedSetNode/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.HashconsedSetNode.Key)

Parameter HashconsedSetNode.Key

type 'key t

The type of generic/heterogeneous keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : 'key t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

val polyeq : 'a t -> 'b t -> ('a, 'b) cmp

Polymorphic equality function used to compare our keys. It should satisfy (to_int a) = (to_int b) ==> polyeq a b = Eq, and be fast.

diff --git a/v0.10.0/PatriciaTree/HashconsedSetNode/index.html b/v0.10.0/PatriciaTree/HashconsedSetNode/index.html new file mode 100644 index 0000000..6c7a04d --- /dev/null +++ b/v0.10.0/PatriciaTree/HashconsedSetNode/index.html @@ -0,0 +1,9 @@ + +HashconsedSetNode (patricia-tree.PatriciaTree.HashconsedSetNode)

Module PatriciaTree.HashconsedSetNode

Both a HashconsedNode and a SetNode.

Parameters

Signature

include NODE with type 'a key = 'a Key.t with type ('key, 'map) value = unit

Types

type 'a key = 'a Key.t

The type of keys.

type ('key, 'map) value = unit

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

val to_int : 'a t -> int

Returns a unique number for each map, the hash-consed identifier of the map. 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 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 HASHED_VALUE.polyeq for details.

val equal : 'a t -> 'a t -> bool

Constant time equality using the 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 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 node identifiers. This order is fully arbitrary, but it is total and can be used to sort nodes. It is based on node ids which depend on the order in which the nodes where created (older nodes having smaller ids).

One useful property of this order is that child nodes will always have a smaller identifier than their parents.

diff --git a/v0.10.0/PatriciaTree/HashedValue/index.html b/v0.10.0/PatriciaTree/HashedValue/index.html new file mode 100644 index 0000000..13e874e --- /dev/null +++ b/v0.10.0/PatriciaTree/HashedValue/index.html @@ -0,0 +1,29 @@ + +HashedValue (patricia-tree.PatriciaTree.HashedValue)

Module PatriciaTree.HashedValue

Generic implementation of HASHED_VALUE. Uses 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 HASHED_VALUE.polyeq for details on this.

type 'a t = 'a

The type of values for a hash-consed maps.

Unlike VALUE.t, 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

val hash : 'map t -> int

hash v should return an integer hash for the value v. It is used for hash-consing.

Hashing should be fast, avoid mapping too many values to the same integer and compatible with polyeq (equal values must have the same hash: polyeq v1 v2 = true ==> hash v1 = hash v2).

val polyeq : 'a t -> 'b t -> bool

Polymorphic equality on values.

WARNING: if polyeq a b is true, then casting b to the type of a (and a to the type of b) must be type-safe. Eg. if a : t1 t and b : t2 t yield polyeq a b = true, then let a' : t2 t = Obj.magic a and let b' : t1 t = Obj.magic b must be safe.

Examples of safe implementations include:

  • Having a type 'a t which doesn't depend on 'a, in which case casting form 'a t to 'b t is always safe:

    type _ t = foo
    +let cast : type a b. a t -> b t = fun x -> x
    +let polyeq : type a b. a t -> b t -> bool = fun x y -> x = y
  • Using a GADT type and examining its constructors to only return true when the constructors are equal:

    type _ t =
    +    | T_Int : int -> int t
    +    | T_Bool : bool -> bool t
    +let polyeq : type a b. a t -> b t -> bool = fun x y ->
    +    match x, y with
    +    | T_Int i, T_Int j -> i = j (* Here type a = b = int, we can return true *)
    +    | T_Bool i, T_Bool j -> i && j (* same here, but with a = b = bool *)
    +    | _ -> false (* never return true on heterogeneous cases. *)
  • Using physical equality:

    let polyeq a b = a == Obj.magic b

    While this contains an Obj.magic, it is still type safe (OCaml just compares the immediate values) and we can safely cast values from one type to the other if they satisfy this (since they are already physically equal).

    This is the implementation used in HashedValue. Note however that using this function can lead to identifiers no longer being unique across types. They will still be unique and behave as expected within a certain type, but since some values of different types can physically equal, we may have identifer clashes:

    # 97 == Obj.magic 'a';;
    +- : bool = true
    module HMap = MakeHashconsedMap(struct
    +    type t = int
    +    let to_int x = x
    +end)(HashedValue)()
    # let m1 = HMap.singleton 5 97;;
    +val m1 : int HMap.t = <abstr>
    +# let m2 = HMap.singleton 5 'a';;
    +val m2 : char HMap.t = <abstr>
    +# HMap.to_int m1 = HMap.to_int m2;;
    +- : bool = true

    This can cause problems if you wish to use identifiers of different map types together:

    type any = Any : 'a HMap.t -> any
    +module MapOfMaps = MakeMap(struct
    +  type t = any
    +  let to_int (Any x) = HMap.to_int x
    +end)

    Using this can lead to unexpected behaviors: in the following m3 has cardinal 1, the m1->"foo" binding has been overwritten

    # let m3 = MapOfMaps.of_list [ (Any m1, "foo"); (Any m2, "bar") ]
    +val m3 : string MapOfMaps.t = <abstr>
    +# MapOfMaps.to_list m3
    +- : (any * string) list = [(Any <abstr>, "bar")]

    This issue does not happen with the two previous variants, since they both only return true on the same types.

diff --git a/v0.10.0/PatriciaTree/HeterogeneousHashedValue/index.html b/v0.10.0/PatriciaTree/HeterogeneousHashedValue/index.html new file mode 100644 index 0000000..d7f3325 --- /dev/null +++ b/v0.10.0/PatriciaTree/HeterogeneousHashedValue/index.html @@ -0,0 +1,13 @@ + +HeterogeneousHashedValue (patricia-tree.PatriciaTree.HeterogeneousHashedValue)

Module PatriciaTree.HeterogeneousHashedValue

Generic implementation of HETEROGENEOUS_HASHED_VALUE. Uses 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 HASHED_VALUE.polyeq for details on this.

type ('k, 'm) t = 'm

The type of values for a hash-consed maps.

Unlike HETEROGENEOUS_VALUE.t, 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

val hash : ('key, 'map) t -> int

hash v should return an integer hash for the value v. It is used for hash-consing.

Hashing should be fast, avoid mapping too many values to the same integer and compatible with polyeq (equal values must have the same hash: polyeq v1 v2 = true ==> hash v1 = hash v2).

val polyeq : ('key, 'map_a) t -> ('key, 'map_b) t -> bool

Polymorphic equality on values.

WARNING: if polyeq a b is true, then casting b to the type of a (and a to the type of b) must be type-safe. Eg. if a : (k, t1) t and b : (k, t2) t yield polyeq a b = true, then let a' : (k,t2) t = Obj.magic a and let b' : (k,t1) t = Obj.magic b must be safe.

Examples of safe implementations include:

  • Having a type ('key, 'map) t which doesn't depend on 'map (i can depend on 'key), in which case casting form ('key, 'a) t to ('key, 'b) t is always safe:

    type ('k, _) t = 'k list
    +let cast : type a b. ('k, a) t -> ('k, b) t = fun x -> x
    +let polyeq : type a b. ('k, a) t -> ('k, b) t -> bool = fun x y -> x = y
  • Using a GADT type and examining its constructors to only return true when the constructors are equal:

    type (_, _) t =
    +    | T_Int : int -> (unit, int) t
    +    | T_Bool : bool -> (unit, bool) t
    +let polyeq : type k a b. (k, a) t -> (k, b) t -> bool = fun x y ->
    +    match x, y with
    +    | T_Int i, T_Int j -> i = j (* Here type a = b = int, we can return true *)
    +    | T_Bool i, T_Bool j -> i && j (* same here, but with a = b = bool *)
    +    | _ -> false (* never return true on heterogeneous cases. *)
  • Using physical equality:

    let polyeq a b = a == Obj.magic b

    While this contains an Obj.magic, it is still type safe (OCaml just compares the immediate values) and we can safely cast values from one type to the other if they satisfy this (since they are already physically equal).

    This is the implementation used in HeterogeneousHashedValue. Note however that using this function can lead to identifiers no longer being unique across types. See HASHED_VALUE.polyeq for more information on this.

diff --git a/v0.10.0/PatriciaTree/HomogeneousValue/index.html b/v0.10.0/PatriciaTree/HomogeneousValue/index.html new file mode 100644 index 0000000..853748a --- /dev/null +++ b/v0.10.0/PatriciaTree/HomogeneousValue/index.html @@ -0,0 +1,4 @@ + +HomogeneousValue (patricia-tree.PatriciaTree.HomogeneousValue)

Module PatriciaTree.HomogeneousValue

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.

type ('a, 'map) t = 'map

The type of values. A 'map map maps 'key key to ('key, 'map) value. Can be mutable if desired, unless it is being used in Hash-consed maps and sets.

diff --git a/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..03af921 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeCustomHeterogeneousMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/WithForeign/index.html new file mode 100644 index 0000000..988845d --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeCustomHeterogeneousMap.WithForeign)

Module MakeCustomHeterogeneousMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/argument-1-Key/index.html b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/argument-1-Key/index.html new file mode 100644 index 0000000..5945586 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.MakeCustomHeterogeneousMap.Key)

Parameter MakeCustomHeterogeneousMap.Key

type 'key t

The type of generic/heterogeneous keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : 'key t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

val polyeq : 'a t -> 'b t -> ('a, 'b) cmp

Polymorphic equality function used to compare our keys. It should satisfy (to_int a) = (to_int b) ==> polyeq a b = Eq, and be fast.

diff --git a/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/argument-2-Value/index.html b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/argument-2-Value/index.html new file mode 100644 index 0000000..e784b52 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/argument-2-Value/index.html @@ -0,0 +1,4 @@ + +Value (patricia-tree.PatriciaTree.MakeCustomHeterogeneousMap.Value)

Parameter MakeCustomHeterogeneousMap.Value

type ('key, 'map) t

The type of values. A 'map map maps 'key key to ('key, 'map) value. Can be mutable if desired, unless it is being used in Hash-consed maps and sets.

diff --git a/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/argument-3-Node/index.html b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/argument-3-Node/index.html new file mode 100644 index 0000000..65ba0f6 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/argument-3-Node/index.html @@ -0,0 +1,9 @@ + +Node (patricia-tree.PatriciaTree.MakeCustomHeterogeneousMap.Node)

Parameter MakeCustomHeterogeneousMap.Node

We use a uniform type 'map view to pattern match on maps and sets The actual types 'map t can be a bit different from 'map view to allow for more efficient representations, but view should be a constant time operation for quick conversions.

Types

type 'a key = 'a Key.t

The type of keys.

type ('key, 'map) value = ('key, 'map) Value.t

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

diff --git a/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/index.html b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/index.html new file mode 100644 index 0000000..dd80fe5 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousMap/index.html @@ -0,0 +1,78 @@ + +MakeCustomHeterogeneousMap (patricia-tree.PatriciaTree.MakeCustomHeterogeneousMap)

Module PatriciaTree.MakeCustomHeterogeneousMap

Create an heterogeneous map with a custom NODE.

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 MAP are:

Parameters

module Node : + NODE + with type 'a key = 'a Key.t + and type ('key, 'map) value = ('key, 'map) Value.t

Signature

include BASE_MAP + with type 'a key = 'a Key.t + with type ('k, 'm) value = ('k, 'm) Value.t + with type 'm t = 'm Node.t
include NODE + with type 'a key = 'a Key.t + with type ('k, 'm) value = ('k, 'm) Value.t + with type 'm t = 'm Node.t

Types

type 'a key = 'a Key.t

The type of keys.

type ('k, 'm) value = ('k, 'm) Value.t

The type of value, which depends on the type of the key and the type of the map.

type 'm t = 'm Node.t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/BaseMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/BaseMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..6438c29 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/BaseMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeCustomHeterogeneousSet.BaseMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/BaseMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/BaseMap/WithForeign/index.html new file mode 100644 index 0000000..6893a0d --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/BaseMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeCustomHeterogeneousSet.BaseMap.WithForeign)

Module BaseMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/BaseMap/index.html b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/BaseMap/index.html new file mode 100644 index 0000000..8911a9d --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/BaseMap/index.html @@ -0,0 +1,75 @@ + +BaseMap (patricia-tree.PatriciaTree.MakeCustomHeterogeneousSet.BaseMap)

Module MakeCustomHeterogeneousSet.BaseMap

Underlying basemap, for cross map/set operations

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 MAP are:

include BASE_MAP + with type 'a key = 'a elt + with type (_, _) value = unit + with type 'a t = 'a NODE.t
include NODE + with type 'a key = 'a elt + with type (_, _) value = unit + with type 'a t = 'a NODE.t

Types

type 'a key = 'a elt

The type of keys.

type (_, _) value = unit

The type of value, which depends on the type of the key and the type of the map.

type 'a t = 'a NODE.t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/argument-1-Key/index.html b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/argument-1-Key/index.html new file mode 100644 index 0000000..4513084 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.MakeCustomHeterogeneousSet.Key)

Parameter MakeCustomHeterogeneousSet.Key

type 'key t

The type of generic/heterogeneous keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : 'key t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

val polyeq : 'a t -> 'b t -> ('a, 'b) cmp

Polymorphic equality function used to compare our keys. It should satisfy (to_int a) = (to_int b) ==> polyeq a b = Eq, and be fast.

diff --git a/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/argument-2-NODE/index.html b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/argument-2-NODE/index.html new file mode 100644 index 0000000..a0e8f5f --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/argument-2-NODE/index.html @@ -0,0 +1,9 @@ + +NODE (patricia-tree.PatriciaTree.MakeCustomHeterogeneousSet.NODE)

Parameter MakeCustomHeterogeneousSet.NODE

We use a uniform type 'map view to pattern match on maps and sets The actual types 'map t can be a bit different from 'map view to allow for more efficient representations, but view should be a constant time operation for quick conversions.

Types

type 'a key = 'a Key.t

The type of keys.

type ('key, 'map) value = unit

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

diff --git a/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/index.html b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/index.html new file mode 100644 index 0000000..b8f75bc --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomHeterogeneousSet/index.html @@ -0,0 +1,13 @@ + +MakeCustomHeterogeneousSet (patricia-tree.PatriciaTree.MakeCustomHeterogeneousSet)

Module PatriciaTree.MakeCustomHeterogeneousSet

Create an heterogeneous set with a custom NODE.

A set containing different keys, very similar to SET, but with simple type elt being replaced by type constructor 'a elt.

Parameters

module NODE : NODE with type 'a key = 'a Key.t and type ('key, 'map) value = unit

Signature

The main changes from SET are:

type 'a elt = 'a Key.t

Elements of the set

module BaseMap : + HETEROGENEOUS_MAP + with type 'a key = 'a elt + and type (_, _) value = unit + with type 'a t = 'a NODE.t

Underlying basemap, for cross map/set operations

type t = unit BaseMap.t

The type of our set

type 'a key = 'a elt

Alias for elements, for compatibility with other PatriciaTrees

type any_elt =
  1. | Any : 'a elt -> any_elt

Existential wrapper for set elements.

Basic functions

val empty : t

The empty set

val is_empty : t -> bool

is_empty st is true if st contains no elements, false otherwise

val mem : 'a elt -> t -> bool

mem elt set is true if elt is contained in set, O(log(n)) complexity.

val add : 'a elt -> t -> t

add elt set adds element elt to the set. Preserves physical equality if elt was already present. O(log(n)) complexity.

val singleton : 'a elt -> t

singleton elt returns a set containing a single element: elt

val cardinal : t -> int

the size of the set (number of elements), O(n) complexity.

val is_singleton : t -> any_elt option

is_singleton set is Some (Any elt) if set is singleton elt and None otherwise.

val remove : 'a elt -> t -> t

remove elt set returns a set containing all elements of set except elt. Returns a value physically equal to set if elt is not present.

val unsigned_min_elt : t -> any_elt

The minimal element if non empty, according to the unsigned order on elements.

  • raises Not_found
val unsigned_max_elt : t -> any_elt

The maximal element if non empty, according to the unsigned order on elements.

  • raises Not_found
val pop_unsigned_minimum : t -> (any_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 order on elements.

val pop_unsigned_maximum : t -> (any_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 order on elements.

Functions on pairs of sets

val union : t -> t -> t

union a b is the set union of a and b, i.e. the set containing all elements that are either in a or b.

val inter : t -> t -> t

inter a b is the set intersection of a and b, i.e. the set containing all elements that are in both a or b.

val disjoint : t -> t -> bool

disjoint a b is true if a and b have no elements in common.

val equal : t -> t -> bool

equal a b is true if a and b contain the same elements.

val subset : t -> t -> bool

subset a b is true if all elements of a are also in b.

val split : 'a 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 order on elements.

Iterators

type polyiter = {
  1. f : 'a. 'a elt -> unit;
}
val iter : polyiter -> t -> unit

iter f set calls f.f on all elements of set, in the unsigned order of KEY.to_int.

type polypredicate = {
  1. f : 'a. 'a elt -> bool;
}
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 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 order of KEY.to_int.

type 'acc polyfold = {
  1. f : 'a. 'a elt -> 'acc -> 'acc;
}
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 order of KEY.to_int

type polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a elt -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + polypretty -> + Stdlib.Format.formatter -> + t -> + unit

Pretty prints the set, pp_sep is called once between each element, it defaults to Format.pp_print_cut

Conversion functions

val to_seq : t -> any_elt Stdlib.Seq.t

to_seq st iterates the whole set, in increasing unsigned order of KEY.to_int

val to_rev_seq : t -> any_elt Stdlib.Seq.t

to_rev_seq st iterates the whole set, in decreasing unsigned order of KEY.to_int

val add_seq : any_elt Stdlib.Seq.t -> t -> t

add_seq s st adds all elements of the sequence s to st in order.

val of_seq : any_elt Stdlib.Seq.t -> t

of_seq s creates a new set from the elements of s.

val of_list : any_elt list -> t

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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeCustomMap/BaseMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeCustomMap/BaseMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..2beb704 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomMap/BaseMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeCustomMap.BaseMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeCustomMap/BaseMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeCustomMap/BaseMap/WithForeign/index.html new file mode 100644 index 0000000..ad12682 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomMap/BaseMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeCustomMap.BaseMap.WithForeign)

Module BaseMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeCustomMap/BaseMap/index.html b/v0.10.0/PatriciaTree/MakeCustomMap/BaseMap/index.html new file mode 100644 index 0000000..a1cef87 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomMap/BaseMap/index.html @@ -0,0 +1,75 @@ + +BaseMap (patricia-tree.PatriciaTree.MakeCustomMap.BaseMap)

Module MakeCustomMap.BaseMap

Underlying basemap, for cross map/set operations

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 MAP are:

include BASE_MAP + with type 'a t = 'a t + with type _ key = key + with type ('a, 'b) value = ('a, 'b value) snd
include NODE + with type 'a t = 'a t + with type _ key = key + with type ('a, 'b) value = ('a, 'b value) snd

Types

type _ key = key

The type of keys.

type ('a, 'b) value = ('a, 'b value) snd

The type of value, which depends on the type of the key and the type of the map.

type 'a t = 'a t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/MakeCustomMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeCustomMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..2e3f60d --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeCustomMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type _ key = key

Types

type _ key = key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeCustomMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeCustomMap/WithForeign/index.html new file mode 100644 index 0000000..beebc96 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomMap/WithForeign/index.html @@ -0,0 +1,19 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeCustomMap.WithForeign)

Module MakeCustomMap.WithForeign

Combination with other kinds of maps. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type _ key = key

Signature

type ('b, 'c) polyfilter_map_foreign = {
  1. f : 'a. key -> ('a, 'b) Map2.value -> 'c value option;
}
val filter_map_no_share : ('b, 'c) polyfilter_map_foreign -> 'b Map2.t -> 'c t

Like filter_map_no_share, but takes another map.

type ('value, 'map2) polyinter_foreign = {
  1. f : 'a. 'a Map2.key -> 'value value -> ('a, 'map2) Map2.value -> 'value value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like nonidempotent_inter, but takes another map as an argument.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. key -> + 'map1 value option -> + ('a, 'map2) Map2.value -> + 'map1 value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update (but more efficient) update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. key -> 'map1 value -> ('a, 'map2) Map2.value -> 'map1 value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeCustomMap/argument-1-Key/index.html b/v0.10.0/PatriciaTree/MakeCustomMap/argument-1-Key/index.html new file mode 100644 index 0000000..cb92e38 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomMap/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.MakeCustomMap.Key)

Parameter MakeCustomMap.Key

type t

The type of keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

diff --git a/v0.10.0/PatriciaTree/MakeCustomMap/argument-2-Value/index.html b/v0.10.0/PatriciaTree/MakeCustomMap/argument-2-Value/index.html new file mode 100644 index 0000000..bb5d675 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomMap/argument-2-Value/index.html @@ -0,0 +1,4 @@ + +Value (patricia-tree.PatriciaTree.MakeCustomMap.Value)

Parameter MakeCustomMap.Value

type 'a t

The type of values. A 'map map maps key to 'map value. Can be mutable if desired, unless it is being used in Hash-consed maps and sets.

diff --git a/v0.10.0/PatriciaTree/MakeCustomMap/argument-3-Node/index.html b/v0.10.0/PatriciaTree/MakeCustomMap/argument-3-Node/index.html new file mode 100644 index 0000000..b371530 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomMap/argument-3-Node/index.html @@ -0,0 +1,9 @@ + +Node (patricia-tree.PatriciaTree.MakeCustomMap.Node)

Parameter MakeCustomMap.Node

We use a uniform type 'map view to pattern match on maps and sets The actual types 'map t can be a bit different from 'map view to allow for more efficient representations, but view should be a constant time operation for quick conversions.

Types

type 'a key = Key.t

The type of keys.

type ('key, 'map) value = ('key, 'map Value.t) snd

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

diff --git a/v0.10.0/PatriciaTree/MakeCustomMap/index.html b/v0.10.0/PatriciaTree/MakeCustomMap/index.html new file mode 100644 index 0000000..0b37298 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomMap/index.html @@ -0,0 +1,60 @@ + +MakeCustomMap (patricia-tree.PatriciaTree.MakeCustomMap)

Module PatriciaTree.MakeCustomMap

Create a homogeneous map with a custom NODE. Also allows customizing the map values

Parameters

module Key : KEY
module Value : VALUE
module Node : + NODE + with type 'a key = Key.t + and type ('key, 'map) value = ('key, 'map Value.t) snd

Signature

type key = Key.t

The type of keys.

type 'm t = 'm Node.t

A map from key to values of type 'a value.

type 'm value = 'm Value.t

Type for values, this is a divergence from Stdlib's 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.

  • since v0.10.0
module BaseMap : + HETEROGENEOUS_MAP + with type 'a t = 'a t + and type _ key = key + and type ('a, 'b) value = ('a, 'b value) snd

Underlying basemap, for cross map/set operations

Basic functions

val empty : 'a t

The empty map.

val is_empty : 'a t -> bool

Test if a map is empty; O(1) complexity.

val unsigned_min_binding : 'a t -> key * 'a value

Returns the (key,value) pair where Key.to_int key is minimal (in the unsigned representation of integers); O(log n) complexity.

  • raises Not_found

    if the map is empty.

val unsigned_max_binding : 'a t -> key * 'a value

Returns the (key,value) pair where Key.to_int key is maximal (in the unsigned representation of integers); O(log n) complexity.

  • raises Not_found

    if the map is empty.

val singleton : key -> 'a value -> 'a t

singleton key value creates a map with a single binding, O(1) complexity.

val cardinal : 'a t -> int

The size of the map. O(n) complexity.

val is_singleton : 'a t -> (key * 'a value) option

is_singleton m is Some (k,v) iff m is singleton k v.

val find : key -> 'a t -> 'a value

Return an element in the map, or raise Not_found, O(log(n)) complexity.

val find_opt : key -> 'a t -> 'a value option

Return an element in the map, or None, O(log(n)) complexity.

val mem : key -> 'a t -> bool

mem key map returns true if and only if key is bound in map. O(log(n)) complexity.

val remove : key -> 'a t -> 'a t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 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 takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : key -> ('a value option -> 'a value option) -> 'a t -> 'a t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : key -> 'a value -> 'a t -> 'a t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : key -> 'a t -> 'a t * 'a value option * 'a t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Uses the 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 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 order of KEY.to_int.

val fold_on_nonequal_inter : + (key -> 'a value -> 'a value -> 'acc -> 'acc) -> + 'a t -> + 'a t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 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

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the 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 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 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 the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

val map : ('a value -> 'a value) -> 'a t -> 'a t

map f m returns a map where the value bound to each key is replaced by f value. The subtrees for which the returned 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 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 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 replaced by f key value. The subtrees for which the returned 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 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 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 key is removed (if f key value returns None), or is replaced by v ((if f key value returns Some v). The subtrees for which the returned value is physically the same (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 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 order of KEY.to_int.

Operations on pairs of maps

The following functions combine two maps. It is key for the performance, when we have large maps who share common subtrees, not to visit the nodes in these subtrees. Hence, we have specialized versions of these functions that assume properties of the function parameter (reflexive relation, idempotent operation, etc.)

When we cannot enjoy these properties, our functions explicitly say so (with a nonreflexive or nonidempotent prefix). The names are a bit long, but having these names avoids using an ineffective code by default, by forcing to know and choose between the fast and slow version.

It is also important to not visit a subtree when there merging this subtree with Empty; hence we provide union and inter operations.

val reflexive_same_domain_for_all2 : + (key -> 'a value -> 'a value -> bool) -> + 'a t -> + 'a t -> + bool

reflexive_same_domain_for_all2 f map1 map2 returns true if map1 and map2 have the same keys, and f key value1 value2 returns true for each mapping pair of keys. We assume that f is reflexive (i.e. f key value value returns true) to avoid visiting physically equal subtrees of map1 and map2. The complexity is O(log(n)*Delta) where Delta is the number of different keys between map1 and map2.

val nonreflexive_same_domain_for_all2 : + (key -> 'a value -> 'b value -> bool) -> + 'a t -> + 'b t -> + bool

nonreflexive_same_domain_for_all2 f map1 map2 returns true if map1 and map2 have the same keys, and f key value1 value2 returns true for each mapping pair of keys. The complexity is O(min(|map1|,|map2|)).

val reflexive_subset_domain_for_all2 : + (key -> 'a value -> 'a value -> bool) -> + 'a t -> + 'a t -> + bool

reflexive_subset_domain_for_all2 f map1 map2 returns true if all the keys of map1 also are in map2, and f key (find map1 + key) (find map2 key) returns true when both keys are present in the map. We assume that f is reflexive (i.e. f key value + value returns true) to avoid visiting physically equal subtrees of map1 and map2. The complexity is O(log(n)*Delta) where Delta is the number of different keys between map1 and map2.

val idempotent_union : + (key -> 'a value -> 'a value -> 'a value) -> + 'a t -> + 'a t -> + 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. We assume that f is idempotent (i.e. f key value value == value) to avoid visiting physically equal subtrees of map1 and map2, and also to 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 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

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. We assume that f is idempotent (i.e. f key value value == value) to avoid visiting physically equal subtrees of map1 and map2, and also to 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 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

nonidempotent_inter_no_share f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. f does not 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 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

idempotent_inter_filter f m1 m2 is like idempotent_inter (assuming idempotence, using and preserving physically equal subtrees), but it also removes the key->value bindings for which f returns None.

val slow_merge : + (key -> 'a value option -> 'b value option -> 'c value option) -> + 'a t -> + 'b t -> + 'c t

slow_merge f m1 m2 returns a map whose keys are a subset of the keys of m1 and m2. The f function is used to combine keys, similarly to the Map.merge function. This funcion has to traverse all the bindings in m1 and m2; its complexity is O(|m1|+|m2|). Use one of faster functions above if you can.

val disjoint : 'a t -> 'a t -> bool
module WithForeign (Map2 : BASE_MAP with type _ key = key) : sig ... end

Combination with other kinds of maps. Map2 must use the same KEY.to_int function.

val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + (Stdlib.Format.formatter -> key -> 'a value -> unit) -> + Stdlib.Format.formatter -> + 'a t -> + unit

Pretty prints all bindings of the map. pp_sep is called once between each binding pair and defaults to Format.pp_print_cut.

Conversion functions

val to_seq : 'a t -> (key * 'a value) Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> (key * 'a value) Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : (key * 'a value) Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : (key * 'a value) Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : (key * 'a value) list -> 'a t

of_list l creates a new map from the bindings of l. If a key is bound multiple times in l, the latest binding is kept

val to_list : 'a t -> (key * 'a value) list

to_list m returns the bindings of m as a list, in increasing unsigned order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeCustomSet/BaseMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeCustomSet/BaseMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..bda2f74 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomSet/BaseMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeCustomSet.BaseMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeCustomSet/BaseMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeCustomSet/BaseMap/WithForeign/index.html new file mode 100644 index 0000000..b92267b --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomSet/BaseMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeCustomSet.BaseMap.WithForeign)

Module BaseMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeCustomSet/BaseMap/index.html b/v0.10.0/PatriciaTree/MakeCustomSet/BaseMap/index.html new file mode 100644 index 0000000..11b90f3 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomSet/BaseMap/index.html @@ -0,0 +1,75 @@ + +BaseMap (patricia-tree.PatriciaTree.MakeCustomSet.BaseMap)

Module MakeCustomSet.BaseMap

Underlying basemap, for cross map/set operations

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 MAP are:

include BASE_MAP + with type _ key = elt + with type (_, _) value = unit + with type 'a t = 'a Node.t
include NODE + with type _ key = elt + with type (_, _) value = unit + with type 'a t = 'a Node.t

Types

type _ key = elt

The type of keys.

type (_, _) value = unit

The type of value, which depends on the type of the key and the type of the map.

type 'a t = 'a Node.t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/MakeCustomSet/argument-1-Key/index.html b/v0.10.0/PatriciaTree/MakeCustomSet/argument-1-Key/index.html new file mode 100644 index 0000000..ff1b698 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomSet/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.MakeCustomSet.Key)

Parameter MakeCustomSet.Key

type t

The type of keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

diff --git a/v0.10.0/PatriciaTree/MakeCustomSet/argument-2-Node/index.html b/v0.10.0/PatriciaTree/MakeCustomSet/argument-2-Node/index.html new file mode 100644 index 0000000..7571f94 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomSet/argument-2-Node/index.html @@ -0,0 +1,9 @@ + +Node (patricia-tree.PatriciaTree.MakeCustomSet.Node)

Parameter MakeCustomSet.Node

We use a uniform type 'map view to pattern match on maps and sets The actual types 'map t can be a bit different from 'map view to allow for more efficient representations, but view should be a constant time operation for quick conversions.

Types

type 'a key = Key.t

The type of keys.

type ('key, 'map) value = unit

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

diff --git a/v0.10.0/PatriciaTree/MakeCustomSet/index.html b/v0.10.0/PatriciaTree/MakeCustomSet/index.html new file mode 100644 index 0000000..8005fac --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeCustomSet/index.html @@ -0,0 +1,13 @@ + +MakeCustomSet (patricia-tree.PatriciaTree.MakeCustomSet)

Module PatriciaTree.MakeCustomSet

Create a homogeneous set with a custom NODE.

Parameters

module Key : KEY
module Node : NODE with type 'a key = Key.t and type ('key, 'map) value = unit

Signature

type elt = Key.t

The type of elements of the set

type key = elt

Alias for the type of elements, for cross-compatibility with maps

module BaseMap : + HETEROGENEOUS_MAP + with type _ key = elt + and type (_, _) value = unit + with type 'a t = 'a Node.t

Underlying basemap, for cross map/set operations

type t = unit BaseMap.t

The set type

Basic functions

val empty : t

The empty set

val is_empty : t -> bool

is_empty st is true if st contains no elements, false otherwise

val mem : elt -> t -> bool

mem elt set is true if elt is contained in set, O(log(n)) complexity.

val add : elt -> t -> t

add elt set adds element elt to the set. Preserves physical equality if elt was already present. O(log(n)) complexity.

val singleton : elt -> t

singleton elt returns a set containing a single element: elt

val cardinal : t -> int

cardinal set is the size of the set (number of elements), O(n) complexity.

val is_singleton : t -> elt option

is_singleton set is Some (Any elt) if set is singleton elt and None otherwise.

val remove : elt -> t -> t

remove elt set returns a set containing all elements of set except elt. 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 order on KEY.to_int) if non empty.

  • raises Not_found
val unsigned_max_elt : t -> elt

The maximal element (according to the 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 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 order on KEY.to_int.

Iterators

val iter : (elt -> unit) -> t -> unit

iter f set calls f on all elements of set, in the 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 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 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 order of 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 order on KEY.to_int.

val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + (Stdlib.Format.formatter -> elt -> unit) -> + Stdlib.Format.formatter -> + t -> + unit

Pretty prints the set, pp_sep is called once between each element, it defaults to Format.pp_print_cut

Functions on pairs of sets

val union : t -> t -> t

union a b is the set union of a and b, i.e. the set containing all elements that are either in a or b.

val inter : t -> t -> t

inter a b is the set intersection of a and b, i.e. the set containing all elements that are in both a or b.

val disjoint : t -> t -> bool

disjoint a b is true if a and b have no elements in common.

val equal : t -> t -> bool

equal a b is true if a and b contain the same elements.

val subset : t -> t -> bool

subset a b is true if all elements of a are also in b.

Conversion functions

val to_seq : t -> elt Stdlib.Seq.t

to_seq st iterates the whole set, in increasing unsigned order of KEY.to_int

val to_rev_seq : t -> elt Stdlib.Seq.t

to_rev_seq st iterates the whole set, in decreasing unsigned order of KEY.to_int

val add_seq : elt Stdlib.Seq.t -> t -> t

add_seq s st adds all elements of the sequence s to st in order.

val of_seq : elt Stdlib.Seq.t -> t

of_seq s creates a new set from the elements of s.

val of_list : elt list -> t

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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..23a0b45 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeHashconsedHeterogeneousMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/WithForeign/index.html new file mode 100644 index 0000000..9191fa9 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeHashconsedHeterogeneousMap.WithForeign)

Module MakeHashconsedHeterogeneousMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/argument-1-Key/index.html b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/argument-1-Key/index.html new file mode 100644 index 0000000..ca721e3 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.MakeHashconsedHeterogeneousMap.Key)

Parameter MakeHashconsedHeterogeneousMap.Key

type 'key t

The type of generic/heterogeneous keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : 'key t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

val polyeq : 'a t -> 'b t -> ('a, 'b) cmp

Polymorphic equality function used to compare our keys. It should satisfy (to_int a) = (to_int b) ==> polyeq a b = Eq, and be fast.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/argument-2-Value/index.html b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/argument-2-Value/index.html new file mode 100644 index 0000000..d34e117 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/argument-2-Value/index.html @@ -0,0 +1,13 @@ + +Value (patricia-tree.PatriciaTree.MakeHashconsedHeterogeneousMap.Value)

Parameter MakeHashconsedHeterogeneousMap.Value

type ('key, 'map) t

The type of values for a hash-consed maps.

Unlike HETEROGENEOUS_VALUE.t, 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

val hash : ('key, 'map) t -> int

hash v should return an integer hash for the value v. It is used for hash-consing.

Hashing should be fast, avoid mapping too many values to the same integer and compatible with polyeq (equal values must have the same hash: polyeq v1 v2 = true ==> hash v1 = hash v2).

val polyeq : ('key, 'map_a) t -> ('key, 'map_b) t -> bool

Polymorphic equality on values.

WARNING: if polyeq a b is true, then casting b to the type of a (and a to the type of b) must be type-safe. Eg. if a : (k, t1) t and b : (k, t2) t yield polyeq a b = true, then let a' : (k,t2) t = Obj.magic a and let b' : (k,t1) t = Obj.magic b must be safe.

Examples of safe implementations include:

  • Having a type ('key, 'map) t which doesn't depend on 'map (i can depend on 'key), in which case casting form ('key, 'a) t to ('key, 'b) t is always safe:

    type ('k, _) t = 'k list
    +let cast : type a b. ('k, a) t -> ('k, b) t = fun x -> x
    +let polyeq : type a b. ('k, a) t -> ('k, b) t -> bool = fun x y -> x = y
  • Using a GADT type and examining its constructors to only return true when the constructors are equal:

    type (_, _) t =
    +    | T_Int : int -> (unit, int) t
    +    | T_Bool : bool -> (unit, bool) t
    +let polyeq : type k a b. (k, a) t -> (k, b) t -> bool = fun x y ->
    +    match x, y with
    +    | T_Int i, T_Int j -> i = j (* Here type a = b = int, we can return true *)
    +    | T_Bool i, T_Bool j -> i && j (* same here, but with a = b = bool *)
    +    | _ -> false (* never return true on heterogeneous cases. *)
  • Using physical equality:

    let polyeq a b = a == Obj.magic b

    While this contains an Obj.magic, it is still type safe (OCaml just compares the immediate values) and we can safely cast values from one type to the other if they satisfy this (since they are already physically equal).

    This is the implementation used in HeterogeneousHashedValue. Note however that using this function can lead to identifiers no longer being unique across types. See HASHED_VALUE.polyeq for more information on this.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/index.html b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/index.html new file mode 100644 index 0000000..2e86569 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousMap/index.html @@ -0,0 +1,75 @@ + +MakeHashconsedHeterogeneousMap (patricia-tree.PatriciaTree.MakeHashconsedHeterogeneousMap)

Module PatriciaTree.MakeHashconsedHeterogeneousMap

Hash-consed version of HETEROGENEOUS_MAP. See Hash-consed maps and sets 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 the created nodes, and a reference to store the next unallocated identifier. Maps/sets from different hash-consing functors (even if these functors have the same arguments) will have different (incompatible) numbering systems and be stored in different hash-tables (thus they will never be physically equal).

Parameters

Signature

include HETEROGENEOUS_MAP + with type 'a key = 'a Key.t + and type ('k, 'm) value = ('k, 'm) Value.t
include BASE_MAP + with type 'a key = 'a Key.t + with type ('k, 'm) value = ('k, 'm) Value.t
include NODE + with type 'a key = 'a Key.t + with type ('k, 'm) value = ('k, 'm) Value.t

Types

type 'a key = 'a Key.t

The type of keys.

type ('k, 'm) value = ('k, 'm) Value.t

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

val to_int : 'a t -> int

Returns the hash-consed id of the map. 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 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 HASHED_VALUE.polyeq for details.

val equal : 'a t -> 'a t -> bool

Constant time equality using the 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 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 node identifiers. This order is fully arbitrary, but it is total and can be used to sort nodes. It is based on node ids which depend on the order in which the nodes where created (older nodes having smaller ids).

One useful property of this order is that child nodes will always have a smaller identifier than their parents.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/BaseMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/BaseMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..4dba73a --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/BaseMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeHashconsedHeterogeneousSet.BaseMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/BaseMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/BaseMap/WithForeign/index.html new file mode 100644 index 0000000..9ce66df --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/BaseMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeHashconsedHeterogeneousSet.BaseMap.WithForeign)

Module BaseMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/BaseMap/index.html b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/BaseMap/index.html new file mode 100644 index 0000000..d321b0a --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/BaseMap/index.html @@ -0,0 +1,69 @@ + +BaseMap (patricia-tree.PatriciaTree.MakeHashconsedHeterogeneousSet.BaseMap)

Module MakeHashconsedHeterogeneousSet.BaseMap

Underlying basemap, for cross map/set operations

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 MAP are:

include BASE_MAP with type 'a key = 'a elt with type (_, _) value = unit
include NODE with type 'a key = 'a elt with type (_, _) value = unit

Types

type 'a key = 'a elt

The type of keys.

type (_, _) value = unit

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/argument-1-Key/index.html b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/argument-1-Key/index.html new file mode 100644 index 0000000..8f014c2 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.MakeHashconsedHeterogeneousSet.Key)

Parameter MakeHashconsedHeterogeneousSet.Key

type 'key t

The type of generic/heterogeneous keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : 'key t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

val polyeq : 'a t -> 'b t -> ('a, 'b) cmp

Polymorphic equality function used to compare our keys. It should satisfy (to_int a) = (to_int b) ==> polyeq a b = Eq, and be fast.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/index.html b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/index.html new file mode 100644 index 0000000..24468bb --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedHeterogeneousSet/index.html @@ -0,0 +1,10 @@ + +MakeHashconsedHeterogeneousSet (patricia-tree.PatriciaTree.MakeHashconsedHeterogeneousSet)

Module PatriciaTree.MakeHashconsedHeterogeneousSet

Hash-consed version of HETEROGENEOUS_SET. See Hash-consed maps and sets 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 the created nodes, and a reference to store the next unallocated identifier. Maps/sets from different hash-consing functors (even if these functors have the same arguments) will have different (incompatible) numbering systems and be stored in different hash-tables (thus they will never be physically equal).

Parameters

Signature

include HETEROGENEOUS_SET with type 'a elt = 'a Key.t

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 pass them as arguments (e.g. polyfold, polypretty, etc.)
  • The type of some return values, must be concealed existentially, hence the Any constructor.
type 'a elt = 'a Key.t

Elements of the set

module BaseMap : + HETEROGENEOUS_MAP with type 'a key = 'a elt and type (_, _) value = unit

Underlying basemap, for cross map/set operations

type t = unit BaseMap.t

The type of our set

type 'a key = 'a elt

Alias for elements, for compatibility with other PatriciaTrees

type any_elt =
  1. | Any : 'a elt -> any_elt

Existential wrapper for set elements.

Basic functions

val empty : t

The empty set

val is_empty : t -> bool

is_empty st is true if st contains no elements, false otherwise

val mem : 'a elt -> t -> bool

mem elt set is true if elt is contained in set, O(log(n)) complexity.

val add : 'a elt -> t -> t

add elt set adds element elt to the set. Preserves physical equality if elt was already present. O(log(n)) complexity.

val singleton : 'a elt -> t

singleton elt returns a set containing a single element: elt

val cardinal : t -> int

the size of the set (number of elements), O(n) complexity.

val is_singleton : t -> any_elt option

is_singleton set is Some (Any elt) if set is singleton elt and None otherwise.

val remove : 'a elt -> t -> t

remove elt set returns a set containing all elements of set except elt. Returns a value physically equal to set if elt is not present.

val unsigned_min_elt : t -> any_elt

The minimal element if non empty, according to the unsigned order on elements.

  • raises Not_found
val unsigned_max_elt : t -> any_elt

The maximal element if non empty, according to the unsigned order on elements.

  • raises Not_found
val pop_unsigned_minimum : t -> (any_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 order on elements.

val pop_unsigned_maximum : t -> (any_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 order on elements.

Functions on pairs of sets

val union : t -> t -> t

union a b is the set union of a and b, i.e. the set containing all elements that are either in a or b.

val inter : t -> t -> t

inter a b is the set intersection of a and b, i.e. the set containing all elements that are in both a or b.

val disjoint : t -> t -> bool

disjoint a b is true if a and b have no elements in common.

val subset : t -> t -> bool

subset a b is true if all elements of a are also in b.

val split : 'a 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 order on elements.

Iterators

type polyiter = {
  1. f : 'a. 'a elt -> unit;
}
val iter : polyiter -> t -> unit

iter f set calls f.f on all elements of set, in the unsigned order of KEY.to_int.

type polypredicate = {
  1. f : 'a. 'a elt -> bool;
}
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 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 order of KEY.to_int.

type 'acc polyfold = {
  1. f : 'a. 'a elt -> 'acc -> 'acc;
}
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 order of KEY.to_int

type polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a elt -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + polypretty -> + Stdlib.Format.formatter -> + t -> + unit

Pretty prints the set, pp_sep is called once between each element, it defaults to Format.pp_print_cut

Conversion functions

val to_seq : t -> any_elt Stdlib.Seq.t

to_seq st iterates the whole set, in increasing unsigned order of KEY.to_int

val to_rev_seq : t -> any_elt Stdlib.Seq.t

to_rev_seq st iterates the whole set, in decreasing unsigned order of KEY.to_int

val add_seq : any_elt Stdlib.Seq.t -> t -> t

add_seq s st adds all elements of the sequence s to st in order.

val of_seq : any_elt Stdlib.Seq.t -> t

of_seq s creates a new set from the elements of s.

val of_list : any_elt list -> t

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 order of KEY.to_int

val to_int : t -> int

Returns the hash-consed id of the map. 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 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 HASHED_VALUE.polyeq for details.

val equal : t -> t -> bool

Constant time equality using the 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 KEY.to_int and values are compared by HASHED_VALUE.polyeq.

val compare : t -> t -> int

Constant time comparison using the hash-consed node identifiers. This order is fully arbitrary, but it is total and can be used to sort nodes. It is based on node ids which depend on the order in which the nodes where created (older nodes having smaller ids).

One useful property of this order is that child nodes will always have a smaller identifier than their parents.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedMap/BaseMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeHashconsedMap/BaseMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..ee1e483 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedMap/BaseMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeHashconsedMap.BaseMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedMap/BaseMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeHashconsedMap/BaseMap/WithForeign/index.html new file mode 100644 index 0000000..9c49a18 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedMap/BaseMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeHashconsedMap.BaseMap.WithForeign)

Module BaseMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedMap/BaseMap/index.html b/v0.10.0/PatriciaTree/MakeHashconsedMap/BaseMap/index.html new file mode 100644 index 0000000..e724568 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedMap/BaseMap/index.html @@ -0,0 +1,75 @@ + +BaseMap (patricia-tree.PatriciaTree.MakeHashconsedMap.BaseMap)

Module MakeHashconsedMap.BaseMap

Underlying basemap, for cross map/set operations

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 MAP are:

include BASE_MAP + with type 'a t = 'a t + with type _ key = key + with type ('a, 'b) value = ('a, 'b value) snd
include NODE + with type 'a t = 'a t + with type _ key = key + with type ('a, 'b) value = ('a, 'b value) snd

Types

type _ key = key

The type of keys.

type ('a, 'b) value = ('a, 'b value) snd

The type of value, which depends on the type of the key and the type of the map.

type 'a t = 'a t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeHashconsedMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..14b69ab --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeHashconsedMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type _ key = key

Types

type _ key = key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeHashconsedMap/WithForeign/index.html new file mode 100644 index 0000000..ede0732 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedMap/WithForeign/index.html @@ -0,0 +1,19 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeHashconsedMap.WithForeign)

Module MakeHashconsedMap.WithForeign

Combination with other kinds of maps. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type _ key = key

Signature

type ('b, 'c) polyfilter_map_foreign = {
  1. f : 'a. key -> ('a, 'b) Map2.value -> 'c value option;
}
val filter_map_no_share : ('b, 'c) polyfilter_map_foreign -> 'b Map2.t -> 'c t

Like filter_map_no_share, but takes another map.

type ('value, 'map2) polyinter_foreign = {
  1. f : 'a. 'a Map2.key -> 'value value -> ('a, 'map2) Map2.value -> 'value value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like nonidempotent_inter, but takes another map as an argument.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. key -> + 'map1 value option -> + ('a, 'map2) Map2.value -> + 'map1 value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update (but more efficient) update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. key -> 'map1 value -> ('a, 'map2) Map2.value -> 'map1 value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedMap/argument-1-Key/index.html b/v0.10.0/PatriciaTree/MakeHashconsedMap/argument-1-Key/index.html new file mode 100644 index 0000000..4417a97 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedMap/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.MakeHashconsedMap.Key)

Parameter MakeHashconsedMap.Key

type t

The type of keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedMap/argument-2-Value/index.html b/v0.10.0/PatriciaTree/MakeHashconsedMap/argument-2-Value/index.html new file mode 100644 index 0000000..87f7891 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedMap/argument-2-Value/index.html @@ -0,0 +1,29 @@ + +Value (patricia-tree.PatriciaTree.MakeHashconsedMap.Value)

Parameter MakeHashconsedMap.Value

type 'a t

The type of values for a hash-consed maps.

Unlike VALUE.t, 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

val hash : 'map t -> int

hash v should return an integer hash for the value v. It is used for hash-consing.

Hashing should be fast, avoid mapping too many values to the same integer and compatible with polyeq (equal values must have the same hash: polyeq v1 v2 = true ==> hash v1 = hash v2).

val polyeq : 'a t -> 'b t -> bool

Polymorphic equality on values.

WARNING: if polyeq a b is true, then casting b to the type of a (and a to the type of b) must be type-safe. Eg. if a : t1 t and b : t2 t yield polyeq a b = true, then let a' : t2 t = Obj.magic a and let b' : t1 t = Obj.magic b must be safe.

Examples of safe implementations include:

  • Having a type 'a t which doesn't depend on 'a, in which case casting form 'a t to 'b t is always safe:

    type _ t = foo
    +let cast : type a b. a t -> b t = fun x -> x
    +let polyeq : type a b. a t -> b t -> bool = fun x y -> x = y
  • Using a GADT type and examining its constructors to only return true when the constructors are equal:

    type _ t =
    +    | T_Int : int -> int t
    +    | T_Bool : bool -> bool t
    +let polyeq : type a b. a t -> b t -> bool = fun x y ->
    +    match x, y with
    +    | T_Int i, T_Int j -> i = j (* Here type a = b = int, we can return true *)
    +    | T_Bool i, T_Bool j -> i && j (* same here, but with a = b = bool *)
    +    | _ -> false (* never return true on heterogeneous cases. *)
  • Using physical equality:

    let polyeq a b = a == Obj.magic b

    While this contains an Obj.magic, it is still type safe (OCaml just compares the immediate values) and we can safely cast values from one type to the other if they satisfy this (since they are already physically equal).

    This is the implementation used in HashedValue. Note however that using this function can lead to identifiers no longer being unique across types. They will still be unique and behave as expected within a certain type, but since some values of different types can physically equal, we may have identifer clashes:

    # 97 == Obj.magic 'a';;
    +- : bool = true
    module HMap = MakeHashconsedMap(struct
    +    type t = int
    +    let to_int x = x
    +end)(HashedValue)()
    # let m1 = HMap.singleton 5 97;;
    +val m1 : int HMap.t = <abstr>
    +# let m2 = HMap.singleton 5 'a';;
    +val m2 : char HMap.t = <abstr>
    +# HMap.to_int m1 = HMap.to_int m2;;
    +- : bool = true

    This can cause problems if you wish to use identifiers of different map types together:

    type any = Any : 'a HMap.t -> any
    +module MapOfMaps = MakeMap(struct
    +  type t = any
    +  let to_int (Any x) = HMap.to_int x
    +end)

    Using this can lead to unexpected behaviors: in the following m3 has cardinal 1, the m1->"foo" binding has been overwritten

    # let m3 = MapOfMaps.of_list [ (Any m1, "foo"); (Any m2, "bar") ]
    +val m3 : string MapOfMaps.t = <abstr>
    +# MapOfMaps.to_list m3
    +- : (any * string) list = [(Any <abstr>, "bar")]

    This issue does not happen with the two previous variants, since they both only return true on the same types.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedMap/index.html b/v0.10.0/PatriciaTree/MakeHashconsedMap/index.html new file mode 100644 index 0000000..99cbc35 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedMap/index.html @@ -0,0 +1,57 @@ + +MakeHashconsedMap (patricia-tree.PatriciaTree.MakeHashconsedMap)

Module PatriciaTree.MakeHashconsedMap

Hash-consed version of MAP. See Hash-consed maps and sets 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 the created nodes, and a reference to store the next unallocated identifier. Maps/sets from different hash-consing functors (even if these functors have the same arguments) will have different (incompatible) numbering systems and be stored in different hash-tables (thus they will never be physically equal).

Parameters

module Key : KEY

Signature

include MAP_WITH_VALUE with type key = Key.t and type 'a value = 'a Value.t
type key = Key.t

The type of keys.

type 'a t

A map from key to values of type 'a value.

type 'a value = 'a Value.t

Type for values, this is a divergence from Stdlib's 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.

  • since v0.10.0
module BaseMap : + HETEROGENEOUS_MAP + with type 'a t = 'a t + and type _ key = key + and type ('a, 'b) value = ('a, 'b value) snd

Underlying basemap, for cross map/set operations

Basic functions

val empty : 'a t

The empty map.

val is_empty : 'a t -> bool

Test if a map is empty; O(1) complexity.

val unsigned_min_binding : 'a t -> key * 'a value

Returns the (key,value) pair where Key.to_int key is minimal (in the unsigned representation of integers); O(log n) complexity.

  • raises Not_found

    if the map is empty.

val unsigned_max_binding : 'a t -> key * 'a value

Returns the (key,value) pair where Key.to_int key is maximal (in the unsigned representation of integers); O(log n) complexity.

  • raises Not_found

    if the map is empty.

val singleton : key -> 'a value -> 'a t

singleton key value creates a map with a single binding, O(1) complexity.

val cardinal : 'a t -> int

The size of the map. O(n) complexity.

val is_singleton : 'a t -> (key * 'a value) option

is_singleton m is Some (k,v) iff m is singleton k v.

val find : key -> 'a t -> 'a value

Return an element in the map, or raise Not_found, O(log(n)) complexity.

val find_opt : key -> 'a t -> 'a value option

Return an element in the map, or None, O(log(n)) complexity.

val mem : key -> 'a t -> bool

mem key map returns true if and only if key is bound in map. O(log(n)) complexity.

val remove : key -> 'a t -> 'a t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 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 takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : key -> ('a value option -> 'a value option) -> 'a t -> 'a t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : key -> 'a value -> 'a t -> 'a t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : key -> 'a t -> 'a t * 'a value option * 'a t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Uses the 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 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 order of KEY.to_int.

val fold_on_nonequal_inter : + (key -> 'a value -> 'a value -> 'acc -> 'acc) -> + 'a t -> + 'a t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 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

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the 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 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 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 the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

val map : ('a value -> 'a value) -> 'a t -> 'a t

map f m returns a map where the value bound to each key is replaced by f value. The subtrees for which the returned 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 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 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 replaced by f key value. The subtrees for which the returned 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 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 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 key is removed (if f key value returns None), or is replaced by v ((if f key value returns Some v). The subtrees for which the returned value is physically the same (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 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 order of KEY.to_int.

Operations on pairs of maps

The following functions combine two maps. It is key for the performance, when we have large maps who share common subtrees, not to visit the nodes in these subtrees. Hence, we have specialized versions of these functions that assume properties of the function parameter (reflexive relation, idempotent operation, etc.)

When we cannot enjoy these properties, our functions explicitly say so (with a nonreflexive or nonidempotent prefix). The names are a bit long, but having these names avoids using an ineffective code by default, by forcing to know and choose between the fast and slow version.

It is also important to not visit a subtree when there merging this subtree with Empty; hence we provide union and inter operations.

val reflexive_same_domain_for_all2 : + (key -> 'a value -> 'a value -> bool) -> + 'a t -> + 'a t -> + bool

reflexive_same_domain_for_all2 f map1 map2 returns true if map1 and map2 have the same keys, and f key value1 value2 returns true for each mapping pair of keys. We assume that f is reflexive (i.e. f key value value returns true) to avoid visiting physically equal subtrees of map1 and map2. The complexity is O(log(n)*Delta) where Delta is the number of different keys between map1 and map2.

val nonreflexive_same_domain_for_all2 : + (key -> 'a value -> 'b value -> bool) -> + 'a t -> + 'b t -> + bool

nonreflexive_same_domain_for_all2 f map1 map2 returns true if map1 and map2 have the same keys, and f key value1 value2 returns true for each mapping pair of keys. The complexity is O(min(|map1|,|map2|)).

val reflexive_subset_domain_for_all2 : + (key -> 'a value -> 'a value -> bool) -> + 'a t -> + 'a t -> + bool

reflexive_subset_domain_for_all2 f map1 map2 returns true if all the keys of map1 also are in map2, and f key (find map1 + key) (find map2 key) returns true when both keys are present in the map. We assume that f is reflexive (i.e. f key value + value returns true) to avoid visiting physically equal subtrees of map1 and map2. The complexity is O(log(n)*Delta) where Delta is the number of different keys between map1 and map2.

val idempotent_union : + (key -> 'a value -> 'a value -> 'a value) -> + 'a t -> + 'a t -> + 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. We assume that f is idempotent (i.e. f key value value == value) to avoid visiting physically equal subtrees of map1 and map2, and also to 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 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

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. We assume that f is idempotent (i.e. f key value value == value) to avoid visiting physically equal subtrees of map1 and map2, and also to 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 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

nonidempotent_inter_no_share f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. f does not 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 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

idempotent_inter_filter f m1 m2 is like idempotent_inter (assuming idempotence, using and preserving physically equal subtrees), but it also removes the key->value bindings for which f returns None.

val slow_merge : + (key -> 'a value option -> 'b value option -> 'c value option) -> + 'a t -> + 'b t -> + 'c t

slow_merge f m1 m2 returns a map whose keys are a subset of the keys of m1 and m2. The f function is used to combine keys, similarly to the Map.merge function. This funcion has to traverse all the bindings in m1 and m2; its complexity is O(|m1|+|m2|). Use one of faster functions above if you can.

val disjoint : 'a t -> 'a t -> bool
module WithForeign (Map2 : BASE_MAP with type _ key = key) : sig ... end

Combination with other kinds of maps. Map2 must use the same KEY.to_int function.

val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + (Stdlib.Format.formatter -> key -> 'a value -> unit) -> + Stdlib.Format.formatter -> + 'a t -> + unit

Pretty prints all bindings of the map. pp_sep is called once between each binding pair and defaults to Format.pp_print_cut.

Conversion functions

val to_seq : 'a t -> (key * 'a value) Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> (key * 'a value) Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : (key * 'a value) Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : (key * 'a value) Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : (key * 'a value) list -> 'a t

of_list l creates a new map from the bindings of l. If a key is bound multiple times in l, the latest binding is kept

val to_list : 'a t -> (key * 'a value) list

to_list m returns the bindings of m as a list, in increasing unsigned order of KEY.to_int

val to_int : 'a t -> int

Returns the hash-consed id of the map. 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 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 HASHED_VALUE.polyeq for details.

val equal : 'a t -> 'a t -> bool

Constant time equality using the 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 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 node identifiers. This order is fully arbitrary, but it is total and can be used to sort nodes. It is based on node ids which depend on the order in which the nodes where created (older nodes having smaller ids).

One useful property of this order is that child nodes will always have a smaller identifier than their parents.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedSet/BaseMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeHashconsedSet/BaseMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..6e80e9a --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedSet/BaseMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeHashconsedSet.BaseMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedSet/BaseMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeHashconsedSet/BaseMap/WithForeign/index.html new file mode 100644 index 0000000..2138b6d --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedSet/BaseMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeHashconsedSet.BaseMap.WithForeign)

Module BaseMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedSet/BaseMap/index.html b/v0.10.0/PatriciaTree/MakeHashconsedSet/BaseMap/index.html new file mode 100644 index 0000000..1a7eb67 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedSet/BaseMap/index.html @@ -0,0 +1,69 @@ + +BaseMap (patricia-tree.PatriciaTree.MakeHashconsedSet.BaseMap)

Module MakeHashconsedSet.BaseMap

Underlying basemap, for cross map/set operations

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 MAP are:

include BASE_MAP with type _ key = elt with type (_, _) value = unit
include NODE with type _ key = elt with type (_, _) value = unit

Types

type _ key = elt

The type of keys.

type (_, _) value = unit

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedSet/argument-1-Key/index.html b/v0.10.0/PatriciaTree/MakeHashconsedSet/argument-1-Key/index.html new file mode 100644 index 0000000..3528179 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedSet/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.MakeHashconsedSet.Key)

Parameter MakeHashconsedSet.Key

type t

The type of keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

diff --git a/v0.10.0/PatriciaTree/MakeHashconsedSet/index.html b/v0.10.0/PatriciaTree/MakeHashconsedSet/index.html new file mode 100644 index 0000000..9ec8f42 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHashconsedSet/index.html @@ -0,0 +1,10 @@ + +MakeHashconsedSet (patricia-tree.PatriciaTree.MakeHashconsedSet)

Module PatriciaTree.MakeHashconsedSet

Hash-consed version of SET. See Hash-consed maps and sets 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 the created nodes, and a reference to store the next unallocated identifier. Maps/sets from different hash-consing functors (even if these functors have the same arguments) will have different (incompatible) numbering systems and be stored in different hash-tables (thus they will never be physically equal).

Parameters

module Key : KEY

Signature

include SET with type elt = Key.t
type elt = Key.t

The type of elements of the set

type key = elt

Alias for the type of elements, for cross-compatibility with maps

module BaseMap : + HETEROGENEOUS_MAP with type _ key = elt and type (_, _) value = unit

Underlying basemap, for cross map/set operations

type t = unit BaseMap.t

The set type

Basic functions

val empty : t

The empty set

val is_empty : t -> bool

is_empty st is true if st contains no elements, false otherwise

val mem : elt -> t -> bool

mem elt set is true if elt is contained in set, O(log(n)) complexity.

val add : elt -> t -> t

add elt set adds element elt to the set. Preserves physical equality if elt was already present. O(log(n)) complexity.

val singleton : elt -> t

singleton elt returns a set containing a single element: elt

val cardinal : t -> int

cardinal set is the size of the set (number of elements), O(n) complexity.

val is_singleton : t -> elt option

is_singleton set is Some (Any elt) if set is singleton elt and None otherwise.

val remove : elt -> t -> t

remove elt set returns a set containing all elements of set except elt. 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 order on KEY.to_int) if non empty.

  • raises Not_found
val unsigned_max_elt : t -> elt

The maximal element (according to the 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 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 order on KEY.to_int.

Iterators

val iter : (elt -> unit) -> t -> unit

iter f set calls f on all elements of set, in the 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 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 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 order of 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 order on KEY.to_int.

val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + (Stdlib.Format.formatter -> elt -> unit) -> + Stdlib.Format.formatter -> + t -> + unit

Pretty prints the set, pp_sep is called once between each element, it defaults to Format.pp_print_cut

Functions on pairs of sets

val union : t -> t -> t

union a b is the set union of a and b, i.e. the set containing all elements that are either in a or b.

val inter : t -> t -> t

inter a b is the set intersection of a and b, i.e. the set containing all elements that are in both a or b.

val disjoint : t -> t -> bool

disjoint a b is true if a and b have no elements in common.

val subset : t -> t -> bool

subset a b is true if all elements of a are also in b.

Conversion functions

val to_seq : t -> elt Stdlib.Seq.t

to_seq st iterates the whole set, in increasing unsigned order of KEY.to_int

val to_rev_seq : t -> elt Stdlib.Seq.t

to_rev_seq st iterates the whole set, in decreasing unsigned order of KEY.to_int

val add_seq : elt Stdlib.Seq.t -> t -> t

add_seq s st adds all elements of the sequence s to st in order.

val of_seq : elt Stdlib.Seq.t -> t

of_seq s creates a new set from the elements of s.

val of_list : elt list -> t

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 order of KEY.to_int

val to_int : t -> int

Returns the hash-consed id of the map. 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 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 HASHED_VALUE.polyeq for details.

val equal : t -> t -> bool

Constant time equality using the 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 KEY.to_int and values are compared by HASHED_VALUE.polyeq.

val compare : t -> t -> int

Constant time comparison using the hash-consed node identifiers. This order is fully arbitrary, but it is total and can be used to sort nodes. It is based on node ids which depend on the order in which the nodes where created (older nodes having smaller ids).

One useful property of this order is that child nodes will always have a smaller identifier than their parents.

diff --git a/v0.10.0/PatriciaTree/MakeHeterogeneousMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeHeterogeneousMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..5ebcb54 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHeterogeneousMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeHeterogeneousMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeHeterogeneousMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeHeterogeneousMap/WithForeign/index.html new file mode 100644 index 0000000..d5e5e0e --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHeterogeneousMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeHeterogeneousMap.WithForeign)

Module MakeHeterogeneousMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeHeterogeneousMap/argument-1-Key/index.html b/v0.10.0/PatriciaTree/MakeHeterogeneousMap/argument-1-Key/index.html new file mode 100644 index 0000000..583b52b --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHeterogeneousMap/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.MakeHeterogeneousMap.Key)

Parameter MakeHeterogeneousMap.Key

type 'key t

The type of generic/heterogeneous keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : 'key t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

val polyeq : 'a t -> 'b t -> ('a, 'b) cmp

Polymorphic equality function used to compare our keys. It should satisfy (to_int a) = (to_int b) ==> polyeq a b = Eq, and be fast.

diff --git a/v0.10.0/PatriciaTree/MakeHeterogeneousMap/argument-2-Value/index.html b/v0.10.0/PatriciaTree/MakeHeterogeneousMap/argument-2-Value/index.html new file mode 100644 index 0000000..61101f6 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHeterogeneousMap/argument-2-Value/index.html @@ -0,0 +1,4 @@ + +Value (patricia-tree.PatriciaTree.MakeHeterogeneousMap.Value)

Parameter MakeHeterogeneousMap.Value

type ('key, 'map) t

The type of values. A 'map map maps 'key key to ('key, 'map) value. Can be mutable if desired, unless it is being used in Hash-consed maps and sets.

diff --git a/v0.10.0/PatriciaTree/MakeHeterogeneousMap/index.html b/v0.10.0/PatriciaTree/MakeHeterogeneousMap/index.html new file mode 100644 index 0000000..dc5490e --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHeterogeneousMap/index.html @@ -0,0 +1,73 @@ + +MakeHeterogeneousMap (patricia-tree.PatriciaTree.MakeHeterogeneousMap)

Module PatriciaTree.MakeHeterogeneousMap

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 MAP are:

Parameters

Signature

include BASE_MAP + with type 'a key = 'a Key.t + with type ('k, 'm) value = ('k, 'm) Value.t
include NODE + with type 'a key = 'a Key.t + with type ('k, 'm) value = ('k, 'm) Value.t

Types

type 'a key = 'a Key.t

The type of keys.

type ('k, 'm) value = ('k, 'm) Value.t

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/MakeHeterogeneousSet/BaseMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeHeterogeneousSet/BaseMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..521d4b0 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHeterogeneousSet/BaseMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeHeterogeneousSet.BaseMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeHeterogeneousSet/BaseMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeHeterogeneousSet/BaseMap/WithForeign/index.html new file mode 100644 index 0000000..bcd2c5e --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHeterogeneousSet/BaseMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeHeterogeneousSet.BaseMap.WithForeign)

Module BaseMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeHeterogeneousSet/BaseMap/index.html b/v0.10.0/PatriciaTree/MakeHeterogeneousSet/BaseMap/index.html new file mode 100644 index 0000000..a14a05c --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHeterogeneousSet/BaseMap/index.html @@ -0,0 +1,69 @@ + +BaseMap (patricia-tree.PatriciaTree.MakeHeterogeneousSet.BaseMap)

Module MakeHeterogeneousSet.BaseMap

Underlying basemap, for cross map/set operations

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 MAP are:

include BASE_MAP with type 'a key = 'a elt with type (_, _) value = unit
include NODE with type 'a key = 'a elt with type (_, _) value = unit

Types

type 'a key = 'a elt

The type of keys.

type (_, _) value = unit

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/MakeHeterogeneousSet/argument-1-Key/index.html b/v0.10.0/PatriciaTree/MakeHeterogeneousSet/argument-1-Key/index.html new file mode 100644 index 0000000..a067fd0 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHeterogeneousSet/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.MakeHeterogeneousSet.Key)

Parameter MakeHeterogeneousSet.Key

type 'key t

The type of generic/heterogeneous keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : 'key t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

val polyeq : 'a t -> 'b t -> ('a, 'b) cmp

Polymorphic equality function used to compare our keys. It should satisfy (to_int a) = (to_int b) ==> polyeq a b = Eq, and be fast.

diff --git a/v0.10.0/PatriciaTree/MakeHeterogeneousSet/index.html b/v0.10.0/PatriciaTree/MakeHeterogeneousSet/index.html new file mode 100644 index 0000000..1642d6a --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeHeterogeneousSet/index.html @@ -0,0 +1,10 @@ + +MakeHeterogeneousSet (patricia-tree.PatriciaTree.MakeHeterogeneousSet)

Module PatriciaTree.MakeHeterogeneousSet

A set containing different keys, very similar to SET, but with simple type elt being replaced by type constructor 'a elt.

Parameters

Signature

The main changes from SET are:

type 'a elt = 'a Key.t

Elements of the set

module BaseMap : + HETEROGENEOUS_MAP with type 'a key = 'a elt and type (_, _) value = unit

Underlying basemap, for cross map/set operations

type t = unit BaseMap.t

The type of our set

type 'a key = 'a elt

Alias for elements, for compatibility with other PatriciaTrees

type any_elt =
  1. | Any : 'a elt -> any_elt

Existential wrapper for set elements.

Basic functions

val empty : t

The empty set

val is_empty : t -> bool

is_empty st is true if st contains no elements, false otherwise

val mem : 'a elt -> t -> bool

mem elt set is true if elt is contained in set, O(log(n)) complexity.

val add : 'a elt -> t -> t

add elt set adds element elt to the set. Preserves physical equality if elt was already present. O(log(n)) complexity.

val singleton : 'a elt -> t

singleton elt returns a set containing a single element: elt

val cardinal : t -> int

the size of the set (number of elements), O(n) complexity.

val is_singleton : t -> any_elt option

is_singleton set is Some (Any elt) if set is singleton elt and None otherwise.

val remove : 'a elt -> t -> t

remove elt set returns a set containing all elements of set except elt. Returns a value physically equal to set if elt is not present.

val unsigned_min_elt : t -> any_elt

The minimal element if non empty, according to the unsigned order on elements.

  • raises Not_found
val unsigned_max_elt : t -> any_elt

The maximal element if non empty, according to the unsigned order on elements.

  • raises Not_found
val pop_unsigned_minimum : t -> (any_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 order on elements.

val pop_unsigned_maximum : t -> (any_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 order on elements.

Functions on pairs of sets

val union : t -> t -> t

union a b is the set union of a and b, i.e. the set containing all elements that are either in a or b.

val inter : t -> t -> t

inter a b is the set intersection of a and b, i.e. the set containing all elements that are in both a or b.

val disjoint : t -> t -> bool

disjoint a b is true if a and b have no elements in common.

val equal : t -> t -> bool

equal a b is true if a and b contain the same elements.

val subset : t -> t -> bool

subset a b is true if all elements of a are also in b.

val split : 'a 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 order on elements.

Iterators

type polyiter = {
  1. f : 'a. 'a elt -> unit;
}
val iter : polyiter -> t -> unit

iter f set calls f.f on all elements of set, in the unsigned order of KEY.to_int.

type polypredicate = {
  1. f : 'a. 'a elt -> bool;
}
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 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 order of KEY.to_int.

type 'acc polyfold = {
  1. f : 'a. 'a elt -> 'acc -> 'acc;
}
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 order of KEY.to_int

type polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a elt -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + polypretty -> + Stdlib.Format.formatter -> + t -> + unit

Pretty prints the set, pp_sep is called once between each element, it defaults to Format.pp_print_cut

Conversion functions

val to_seq : t -> any_elt Stdlib.Seq.t

to_seq st iterates the whole set, in increasing unsigned order of KEY.to_int

val to_rev_seq : t -> any_elt Stdlib.Seq.t

to_rev_seq st iterates the whole set, in decreasing unsigned order of KEY.to_int

val add_seq : any_elt Stdlib.Seq.t -> t -> t

add_seq s st adds all elements of the sequence s to st in order.

val of_seq : any_elt Stdlib.Seq.t -> t

of_seq s creates a new set from the elements of s.

val of_list : any_elt list -> t

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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeMap/BaseMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeMap/BaseMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..799e054 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeMap/BaseMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeMap.BaseMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeMap/BaseMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeMap/BaseMap/WithForeign/index.html new file mode 100644 index 0000000..3fccfee --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeMap/BaseMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeMap.BaseMap.WithForeign)

Module BaseMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeMap/BaseMap/index.html b/v0.10.0/PatriciaTree/MakeMap/BaseMap/index.html new file mode 100644 index 0000000..6dd7d9e --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeMap/BaseMap/index.html @@ -0,0 +1,75 @@ + +BaseMap (patricia-tree.PatriciaTree.MakeMap.BaseMap)

Module MakeMap.BaseMap

Underlying basemap, for cross map/set operations

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 MAP are:

include BASE_MAP + with type 'a t = 'a t + with type _ key = key + with type ('a, 'b) value = ('a, 'b value) snd
include NODE + with type 'a t = 'a t + with type _ key = key + with type ('a, 'b) value = ('a, 'b value) snd

Types

type _ key = key

The type of keys.

type ('a, 'b) value = ('a, 'b value) snd

The type of value, which depends on the type of the key and the type of the map.

type 'a t = 'a t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/MakeMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..4d95729 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type _ key = key

Types

type _ key = key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeMap/WithForeign/index.html new file mode 100644 index 0000000..43f4ee0 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeMap/WithForeign/index.html @@ -0,0 +1,19 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeMap.WithForeign)

Module MakeMap.WithForeign

Combination with other kinds of maps. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type _ key = key

Signature

type ('b, 'c) polyfilter_map_foreign = {
  1. f : 'a. key -> ('a, 'b) Map2.value -> 'c value option;
}
val filter_map_no_share : ('b, 'c) polyfilter_map_foreign -> 'b Map2.t -> 'c t

Like filter_map_no_share, but takes another map.

type ('value, 'map2) polyinter_foreign = {
  1. f : 'a. 'a Map2.key -> 'value value -> ('a, 'map2) Map2.value -> 'value value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like nonidempotent_inter, but takes another map as an argument.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. key -> + 'map1 value option -> + ('a, 'map2) Map2.value -> + 'map1 value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update (but more efficient) update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. key -> 'map1 value -> ('a, 'map2) Map2.value -> 'map1 value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeMap/argument-1-Key/index.html b/v0.10.0/PatriciaTree/MakeMap/argument-1-Key/index.html new file mode 100644 index 0000000..a83c7e3 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeMap/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.MakeMap.Key)

Parameter MakeMap.Key

type t

The type of keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

diff --git a/v0.10.0/PatriciaTree/MakeMap/index.html b/v0.10.0/PatriciaTree/MakeMap/index.html new file mode 100644 index 0000000..2251636 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeMap/index.html @@ -0,0 +1,57 @@ + +MakeMap (patricia-tree.PatriciaTree.MakeMap)

Module PatriciaTree.MakeMap

Parameters

module Key : KEY

Signature

type key = Key.t

The type of keys.

type 'a t

A map from key to values of type 'a value.

type 'a value = 'a

Type for values, this is a divergence from Stdlib's 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.

  • since v0.10.0
module BaseMap : + HETEROGENEOUS_MAP + with type 'a t = 'a t + and type _ key = key + and type ('a, 'b) value = ('a, 'b value) snd

Underlying basemap, for cross map/set operations

Basic functions

val empty : 'a t

The empty map.

val is_empty : 'a t -> bool

Test if a map is empty; O(1) complexity.

val unsigned_min_binding : 'a t -> key * 'a value

Returns the (key,value) pair where Key.to_int key is minimal (in the unsigned representation of integers); O(log n) complexity.

  • raises Not_found

    if the map is empty.

val unsigned_max_binding : 'a t -> key * 'a value

Returns the (key,value) pair where Key.to_int key is maximal (in the unsigned representation of integers); O(log n) complexity.

  • raises Not_found

    if the map is empty.

val singleton : key -> 'a value -> 'a t

singleton key value creates a map with a single binding, O(1) complexity.

val cardinal : 'a t -> int

The size of the map. O(n) complexity.

val is_singleton : 'a t -> (key * 'a value) option

is_singleton m is Some (k,v) iff m is singleton k v.

val find : key -> 'a t -> 'a value

Return an element in the map, or raise Not_found, O(log(n)) complexity.

val find_opt : key -> 'a t -> 'a value option

Return an element in the map, or None, O(log(n)) complexity.

val mem : key -> 'a t -> bool

mem key map returns true if and only if key is bound in map. O(log(n)) complexity.

val remove : key -> 'a t -> 'a t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 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 takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : key -> ('a value option -> 'a value option) -> 'a t -> 'a t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : key -> 'a value -> 'a t -> 'a t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : key -> 'a t -> 'a t * 'a value option * 'a t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Uses the 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 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 order of KEY.to_int.

val fold_on_nonequal_inter : + (key -> 'a value -> 'a value -> 'acc -> 'acc) -> + 'a t -> + 'a t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 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

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the 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 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 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 the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

val map : ('a value -> 'a value) -> 'a t -> 'a t

map f m returns a map where the value bound to each key is replaced by f value. The subtrees for which the returned 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 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 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 replaced by f key value. The subtrees for which the returned 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 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 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 key is removed (if f key value returns None), or is replaced by v ((if f key value returns Some v). The subtrees for which the returned value is physically the same (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 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 order of KEY.to_int.

Operations on pairs of maps

The following functions combine two maps. It is key for the performance, when we have large maps who share common subtrees, not to visit the nodes in these subtrees. Hence, we have specialized versions of these functions that assume properties of the function parameter (reflexive relation, idempotent operation, etc.)

When we cannot enjoy these properties, our functions explicitly say so (with a nonreflexive or nonidempotent prefix). The names are a bit long, but having these names avoids using an ineffective code by default, by forcing to know and choose between the fast and slow version.

It is also important to not visit a subtree when there merging this subtree with Empty; hence we provide union and inter operations.

val reflexive_same_domain_for_all2 : + (key -> 'a value -> 'a value -> bool) -> + 'a t -> + 'a t -> + bool

reflexive_same_domain_for_all2 f map1 map2 returns true if map1 and map2 have the same keys, and f key value1 value2 returns true for each mapping pair of keys. We assume that f is reflexive (i.e. f key value value returns true) to avoid visiting physically equal subtrees of map1 and map2. The complexity is O(log(n)*Delta) where Delta is the number of different keys between map1 and map2.

val nonreflexive_same_domain_for_all2 : + (key -> 'a value -> 'b value -> bool) -> + 'a t -> + 'b t -> + bool

nonreflexive_same_domain_for_all2 f map1 map2 returns true if map1 and map2 have the same keys, and f key value1 value2 returns true for each mapping pair of keys. The complexity is O(min(|map1|,|map2|)).

val reflexive_subset_domain_for_all2 : + (key -> 'a value -> 'a value -> bool) -> + 'a t -> + 'a t -> + bool

reflexive_subset_domain_for_all2 f map1 map2 returns true if all the keys of map1 also are in map2, and f key (find map1 + key) (find map2 key) returns true when both keys are present in the map. We assume that f is reflexive (i.e. f key value + value returns true) to avoid visiting physically equal subtrees of map1 and map2. The complexity is O(log(n)*Delta) where Delta is the number of different keys between map1 and map2.

val idempotent_union : + (key -> 'a value -> 'a value -> 'a value) -> + 'a t -> + 'a t -> + 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. We assume that f is idempotent (i.e. f key value value == value) to avoid visiting physically equal subtrees of map1 and map2, and also to 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 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

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. We assume that f is idempotent (i.e. f key value value == value) to avoid visiting physically equal subtrees of map1 and map2, and also to 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 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

nonidempotent_inter_no_share f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. f does not 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 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

idempotent_inter_filter f m1 m2 is like idempotent_inter (assuming idempotence, using and preserving physically equal subtrees), but it also removes the key->value bindings for which f returns None.

val slow_merge : + (key -> 'a value option -> 'b value option -> 'c value option) -> + 'a t -> + 'b t -> + 'c t

slow_merge f m1 m2 returns a map whose keys are a subset of the keys of m1 and m2. The f function is used to combine keys, similarly to the Map.merge function. This funcion has to traverse all the bindings in m1 and m2; its complexity is O(|m1|+|m2|). Use one of faster functions above if you can.

val disjoint : 'a t -> 'a t -> bool
module WithForeign (Map2 : BASE_MAP with type _ key = key) : sig ... end

Combination with other kinds of maps. Map2 must use the same KEY.to_int function.

val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + (Stdlib.Format.formatter -> key -> 'a value -> unit) -> + Stdlib.Format.formatter -> + 'a t -> + unit

Pretty prints all bindings of the map. pp_sep is called once between each binding pair and defaults to Format.pp_print_cut.

Conversion functions

val to_seq : 'a t -> (key * 'a value) Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> (key * 'a value) Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : (key * 'a value) Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : (key * 'a value) Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : (key * 'a value) list -> 'a t

of_list l creates a new map from the bindings of l. If a key is bound multiple times in l, the latest binding is kept

val to_list : 'a t -> (key * 'a value) list

to_list m returns the bindings of m as a list, in increasing unsigned order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeSet/BaseMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/MakeSet/BaseMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..bb3ec56 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeSet/BaseMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MakeSet.BaseMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/MakeSet/BaseMap/WithForeign/index.html b/v0.10.0/PatriciaTree/MakeSet/BaseMap/WithForeign/index.html new file mode 100644 index 0000000..13dc729 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeSet/BaseMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.MakeSet.BaseMap.WithForeign)

Module BaseMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/MakeSet/BaseMap/index.html b/v0.10.0/PatriciaTree/MakeSet/BaseMap/index.html new file mode 100644 index 0000000..83c3a66 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeSet/BaseMap/index.html @@ -0,0 +1,69 @@ + +BaseMap (patricia-tree.PatriciaTree.MakeSet.BaseMap)

Module MakeSet.BaseMap

Underlying basemap, for cross map/set operations

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 MAP are:

include BASE_MAP with type _ key = elt with type (_, _) value = unit
include NODE with type _ key = elt with type (_, _) value = unit

Types

type _ key = elt

The type of keys.

type (_, _) value = unit

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/MakeSet/argument-1-Key/index.html b/v0.10.0/PatriciaTree/MakeSet/argument-1-Key/index.html new file mode 100644 index 0000000..95d7cc9 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeSet/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.MakeSet.Key)

Parameter MakeSet.Key

type t

The type of keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

diff --git a/v0.10.0/PatriciaTree/MakeSet/index.html b/v0.10.0/PatriciaTree/MakeSet/index.html new file mode 100644 index 0000000..52d17e3 --- /dev/null +++ b/v0.10.0/PatriciaTree/MakeSet/index.html @@ -0,0 +1,10 @@ + +MakeSet (patricia-tree.PatriciaTree.MakeSet)

Module PatriciaTree.MakeSet

Parameters

module Key : KEY

Signature

type elt = Key.t

The type of elements of the set

type key = elt

Alias for the type of elements, for cross-compatibility with maps

module BaseMap : + HETEROGENEOUS_MAP with type _ key = elt and type (_, _) value = unit

Underlying basemap, for cross map/set operations

type t = unit BaseMap.t

The set type

Basic functions

val empty : t

The empty set

val is_empty : t -> bool

is_empty st is true if st contains no elements, false otherwise

val mem : elt -> t -> bool

mem elt set is true if elt is contained in set, O(log(n)) complexity.

val add : elt -> t -> t

add elt set adds element elt to the set. Preserves physical equality if elt was already present. O(log(n)) complexity.

val singleton : elt -> t

singleton elt returns a set containing a single element: elt

val cardinal : t -> int

cardinal set is the size of the set (number of elements), O(n) complexity.

val is_singleton : t -> elt option

is_singleton set is Some (Any elt) if set is singleton elt and None otherwise.

val remove : elt -> t -> t

remove elt set returns a set containing all elements of set except elt. 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 order on KEY.to_int) if non empty.

  • raises Not_found
val unsigned_max_elt : t -> elt

The maximal element (according to the 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 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 order on KEY.to_int.

Iterators

val iter : (elt -> unit) -> t -> unit

iter f set calls f on all elements of set, in the 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 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 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 order of 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 order on KEY.to_int.

val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + (Stdlib.Format.formatter -> elt -> unit) -> + Stdlib.Format.formatter -> + t -> + unit

Pretty prints the set, pp_sep is called once between each element, it defaults to Format.pp_print_cut

Functions on pairs of sets

val union : t -> t -> t

union a b is the set union of a and b, i.e. the set containing all elements that are either in a or b.

val inter : t -> t -> t

inter a b is the set intersection of a and b, i.e. the set containing all elements that are in both a or b.

val disjoint : t -> t -> bool

disjoint a b is true if a and b have no elements in common.

val equal : t -> t -> bool

equal a b is true if a and b contain the same elements.

val subset : t -> t -> bool

subset a b is true if all elements of a are also in b.

Conversion functions

val to_seq : t -> elt Stdlib.Seq.t

to_seq st iterates the whole set, in increasing unsigned order of KEY.to_int

val to_rev_seq : t -> elt Stdlib.Seq.t

to_rev_seq st iterates the whole set, in decreasing unsigned order of KEY.to_int

val add_seq : elt Stdlib.Seq.t -> t -> t

add_seq s st adds all elements of the sequence s to st in order.

val of_seq : elt Stdlib.Seq.t -> t

of_seq s creates a new set from the elements of s.

val of_list : elt list -> t

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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/NodeWithId/argument-1-Key/index.html b/v0.10.0/PatriciaTree/NodeWithId/argument-1-Key/index.html new file mode 100644 index 0000000..ef05bcf --- /dev/null +++ b/v0.10.0/PatriciaTree/NodeWithId/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.NodeWithId.Key)

Parameter NodeWithId.Key

type 'k t
diff --git a/v0.10.0/PatriciaTree/NodeWithId/argument-2-Value/index.html b/v0.10.0/PatriciaTree/NodeWithId/argument-2-Value/index.html new file mode 100644 index 0000000..13a9011 --- /dev/null +++ b/v0.10.0/PatriciaTree/NodeWithId/argument-2-Value/index.html @@ -0,0 +1,4 @@ + +Value (patricia-tree.PatriciaTree.NodeWithId.Value)

Parameter NodeWithId.Value

type ('key, 'map) t

The type of values. A 'map map maps 'key key to ('key, 'map) value. Can be mutable if desired, unless it is being used in Hash-consed maps and sets.

diff --git a/v0.10.0/PatriciaTree/NodeWithId/index.html b/v0.10.0/PatriciaTree/NodeWithId/index.html new file mode 100644 index 0000000..1add2d4 --- /dev/null +++ b/v0.10.0/PatriciaTree/NodeWithId/index.html @@ -0,0 +1,11 @@ + +NodeWithId (patricia-tree.PatriciaTree.NodeWithId)

Module PatriciaTree.NodeWithId

Here, nodes also contain a unique id, e.g. so that they can be used as keys of maps or hash-tables.

Parameters

module Key : sig ... end

Signature

include NODE + with type 'a key = 'a Key.t + with type ('key, 'map) value = ('key, 'map) Value.t

Types

type 'a key = 'a Key.t

The type of keys.

type ('key, 'map) value = ('key, 'map) Value.t

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

val to_int : 'a t -> int

Unique number for each node.

This is not hash-consing. Equal nodes created separately will have different identifiers. On the flip side, nodes with equal identifiers will always be physically equal.

diff --git a/v0.10.0/PatriciaTree/SetNode/argument-1-Key/index.html b/v0.10.0/PatriciaTree/SetNode/argument-1-Key/index.html new file mode 100644 index 0000000..1fb95cc --- /dev/null +++ b/v0.10.0/PatriciaTree/SetNode/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.SetNode.Key)

Parameter SetNode.Key

type 'k t
diff --git a/v0.10.0/PatriciaTree/SetNode/index.html b/v0.10.0/PatriciaTree/SetNode/index.html new file mode 100644 index 0000000..d871fac --- /dev/null +++ b/v0.10.0/PatriciaTree/SetNode/index.html @@ -0,0 +1,9 @@ + +SetNode (patricia-tree.PatriciaTree.SetNode)

Module PatriciaTree.SetNode

An optimized representation for sets, i.e. maps to unit: we do not store a reference to unit (note that you can further optimize when you know the representation of the key). This is the node used in MakeHeterogeneousSet and MakeSet.

We use a uniform type 'map view to pattern match on maps and sets The actual types 'map t can be a bit different from 'map view to allow for more efficient representations, but view should be a constant time operation for quick conversions.

Parameters

module Key : sig ... end

Signature

Types

type 'a key = 'a Key.t

The type of keys.

type ('key, 'map) value = unit

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

diff --git a/v0.10.0/PatriciaTree/SimpleNode/argument-1-Key/index.html b/v0.10.0/PatriciaTree/SimpleNode/argument-1-Key/index.html new file mode 100644 index 0000000..d172971 --- /dev/null +++ b/v0.10.0/PatriciaTree/SimpleNode/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.SimpleNode.Key)

Parameter SimpleNode.Key

type 'k t
diff --git a/v0.10.0/PatriciaTree/SimpleNode/argument-2-Value/index.html b/v0.10.0/PatriciaTree/SimpleNode/argument-2-Value/index.html new file mode 100644 index 0000000..fd12c5b --- /dev/null +++ b/v0.10.0/PatriciaTree/SimpleNode/argument-2-Value/index.html @@ -0,0 +1,4 @@ + +Value (patricia-tree.PatriciaTree.SimpleNode.Value)

Parameter SimpleNode.Value

type ('key, 'map) t

The type of values. A 'map map maps 'key key to ('key, 'map) value. Can be mutable if desired, unless it is being used in Hash-consed maps and sets.

diff --git a/v0.10.0/PatriciaTree/SimpleNode/index.html b/v0.10.0/PatriciaTree/SimpleNode/index.html new file mode 100644 index 0000000..ef4be66 --- /dev/null +++ b/v0.10.0/PatriciaTree/SimpleNode/index.html @@ -0,0 +1,9 @@ + +SimpleNode (patricia-tree.PatriciaTree.SimpleNode)

Module PatriciaTree.SimpleNode

This module is such that 'map t = 'map view. This is the node used in MakeHeterogeneousMap and MakeMap.

We use a uniform type 'map view to pattern match on maps and sets The actual types 'map t can be a bit different from 'map view to allow for more efficient representations, but view should be a constant time operation for quick conversions.

Parameters

module Key : sig ... end

Signature

Types

type 'a key = 'a Key.t

The type of keys.

type ('key, 'map) value = ('key, 'map) Value.t

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

diff --git a/v0.10.0/PatriciaTree/Value/index.html b/v0.10.0/PatriciaTree/Value/index.html new file mode 100644 index 0000000..2bf584d --- /dev/null +++ b/v0.10.0/PatriciaTree/Value/index.html @@ -0,0 +1,4 @@ + +Value (patricia-tree.PatriciaTree.Value)

Module PatriciaTree.Value

Default implementation of VALUE, used in MakeMap.

type 'a t = 'a

The type of values. A 'map map maps key to 'map value. Can be mutable if desired, unless it is being used in Hash-consed maps and sets.

diff --git a/v0.10.0/PatriciaTree/WeakNode/argument-1-Key/index.html b/v0.10.0/PatriciaTree/WeakNode/argument-1-Key/index.html new file mode 100644 index 0000000..855e6e3 --- /dev/null +++ b/v0.10.0/PatriciaTree/WeakNode/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.WeakNode.Key)

Parameter WeakNode.Key

type 'k t
diff --git a/v0.10.0/PatriciaTree/WeakNode/argument-2-Value/index.html b/v0.10.0/PatriciaTree/WeakNode/argument-2-Value/index.html new file mode 100644 index 0000000..8a4183a --- /dev/null +++ b/v0.10.0/PatriciaTree/WeakNode/argument-2-Value/index.html @@ -0,0 +1,4 @@ + +Value (patricia-tree.PatriciaTree.WeakNode.Value)

Parameter WeakNode.Value

type ('key, 'map) t

The type of values. A 'map map maps 'key key to ('key, 'map) value. Can be mutable if desired, unless it is being used in Hash-consed maps and sets.

diff --git a/v0.10.0/PatriciaTree/WeakNode/index.html b/v0.10.0/PatriciaTree/WeakNode/index.html new file mode 100644 index 0000000..deefbd5 --- /dev/null +++ b/v0.10.0/PatriciaTree/WeakNode/index.html @@ -0,0 +1,9 @@ + +WeakNode (patricia-tree.PatriciaTree.WeakNode)

Module PatriciaTree.WeakNode

NODE used to implement weak key hashes (the key-binding pair is an Ephemeron, the reference to the key is weak, and if the key is garbage collected, the binding disappears from the map

We use a uniform type 'map view to pattern match on maps and sets The actual types 'map t can be a bit different from 'map view to allow for more efficient representations, but view should be a constant time operation for quick conversions.

Parameters

module Key : sig ... end

Signature

Types

type 'a key = 'a Key.t

The type of keys.

type ('key, 'map) value = ('key, 'map) Value.t

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

diff --git a/v0.10.0/PatriciaTree/WeakSetNode/argument-1-Key/index.html b/v0.10.0/PatriciaTree/WeakSetNode/argument-1-Key/index.html new file mode 100644 index 0000000..9db74ea --- /dev/null +++ b/v0.10.0/PatriciaTree/WeakSetNode/argument-1-Key/index.html @@ -0,0 +1,4 @@ + +Key (patricia-tree.PatriciaTree.WeakSetNode.Key)

Parameter WeakSetNode.Key

type 'k t
diff --git a/v0.10.0/PatriciaTree/WeakSetNode/index.html b/v0.10.0/PatriciaTree/WeakSetNode/index.html new file mode 100644 index 0000000..e3a965c --- /dev/null +++ b/v0.10.0/PatriciaTree/WeakSetNode/index.html @@ -0,0 +1,9 @@ + +WeakSetNode (patricia-tree.PatriciaTree.WeakSetNode)

Module PatriciaTree.WeakSetNode

Both a WeakNode and a SetNode, useful to implement Weak sets.

We use a uniform type 'map view to pattern match on maps and sets The actual types 'map t can be a bit different from 'map view to allow for more efficient representations, but view should be a constant time operation for quick conversions.

Parameters

module Key : sig ... end

Signature

Types

type 'a key = 'a Key.t

The type of keys.

type ('key, 'map) value = unit

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

diff --git a/v0.10.0/PatriciaTree/WrappedHomogeneousValue/index.html b/v0.10.0/PatriciaTree/WrappedHomogeneousValue/index.html new file mode 100644 index 0000000..60232c1 --- /dev/null +++ b/v0.10.0/PatriciaTree/WrappedHomogeneousValue/index.html @@ -0,0 +1,4 @@ + +WrappedHomogeneousValue (patricia-tree.PatriciaTree.WrappedHomogeneousValue)

Module PatriciaTree.WrappedHomogeneousValue

Same as HomogeneousValue, but uses a wrapper (unboxed) type instead of direct equality. This avoids a problem in the typechecker with overly eager simplification of aliases. More info on the OCaml discourse post.

type ('a, 'map) t = ('a, 'map) snd

The type of values. A 'map map maps 'key key to ('key, 'map) value. Can be mutable if desired, unless it is being used in Hash-consed maps and sets.

diff --git a/v0.10.0/PatriciaTree/index.html b/v0.10.0/PatriciaTree/index.html new file mode 100644 index 0000000..dfda024 --- /dev/null +++ b/v0.10.0/PatriciaTree/index.html @@ -0,0 +1,101 @@ + +PatriciaTree (patricia-tree.PatriciaTree)

Module PatriciaTree

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 tree nodes (allowing normal maps, hash-consed maps, weak key or value maps, sets, custom maps, etc.)

This is similar to OCaml's Map, except that:

Note on complexity: in the following, n represents the size of the map when there is one (and |map1| is the number of elements in map1). The term log(n) correspond to the maximum height of the tree, which is log(n) if we assume an even distribution of numbers in the map (e.g. random distribution, or integers chosen contiguously using a counter). The worst-case height is O(min(n,64)) which is actually constant, but not really informative; log(n) corresponds to the real complexity in usual distributions.

val unsigned_lt : int -> int -> bool

All integers comparisons in this library are done according to their unsigned representation. This is the same as signed comparison for same sign integers, but all negative integers are greater than the positives. This means -1 is the greatest possible number, and 0 is the smallest.

# unsigned_lt 2 (-1);;
+- : bool = true
+# unsigned_lt max_int min_int;;
+- : bool = true
+# unsigned_lt 3 2;;
+- : bool = false
+# unsigned_lt 2 3;;
+- : bool = true
+# unsigned_lt (-2) (-3);;
+- : bool = false
+# unsigned_lt (-4) (-3);;
+- : bool = true
+# unsigned_lt 0 0;;
+- : bool = false

Using this unsigned order helps avoid a bug described in QuickChecking Patricia Trees by Jan Mitgaard.

  • since 0.10.0
type intkey = private int

Private type used to represent prefix stored in nodes. These are integers with all bits after branching bit (included) set to zero

type mask = private int

Private type: integers with a single bit set.

Nodes

module type NODE = sig ... end

This module explains how a node is stored in memory, with functions to create and view nodes.

module type NODE_WITH_ID = sig ... end

Associate a unique number to each node, so they can be used as keys in sets or maps.

module type HASH_CONSED_NODE = sig ... end

Hash-consed nodes also associate a unique number to each node, 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.

Map signatures

Base map

module type BASE_MAP = sig ... end

Base map signature: a generic 'b map storing bindings of 'a key to ('a,'b) values. All maps and set are a variation of this type, sometimes with a simplified interface.

Heterogeneous maps and sets

Maps and sets with generic keys 'a key and values ('a,'b) value

module type HETEROGENEOUS_MAP = sig ... end

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.

module type HETEROGENEOUS_SET = sig ... end

A set containing different keys, very similar to SET, but with simple type elt being replaced by type constructor 'a elt.

Homogeneous maps and sets

Same as above, but simple interfaces for non-generic keys. These are also close to the standard library's interface for sets and maps.

module type SET = sig ... end

Signature for sets implemented using Patricia trees. Most of this interface should be shared with Stdlib.Set.S.

type (_, 'b) snd =
  1. | Snd of 'b

The typechecker struggles with forall quantification on values if they don't depend on the first parameter, this wrapping allows our code to pass typechecking by forbidding overly eager simplification. Since the type is unboxed, it doesn't introduce any performance overhead.

This is due to a bug in the typechecker, more info on the OCaml discourse post.

module type MAP_WITH_VALUE = sig ... end

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 MAP, which just binds to 'a. It is used for maps that need to restrict their value type, namely Hash-consed maps and sets.

module type MAP = MAP_WITH_VALUE with type 'a value = 'a

The signature for maps with a single type for keys and values, a 'a map binds key to 'a. Most of this interface should be shared with Stdlib.Map.S.

Keys

Keys are the functor arguments used to build the maps.

module type KEY = sig ... end

The signature of homogeneous keys (non-generic, unparameterized keys).

type (_, _) cmp =
  1. | Eq : ('a, 'a) cmp
  2. | Diff : ('a, 'b) cmp

To have heterogeneous keys, we must define a polymorphic equality function. Like in the homogeneous case, it should have the requirement that (to_int a) = (to_int b) ==> polyeq a b = Eq.

module type HETEROGENEOUS_KEY = sig ... end

The signature of heterogeneous keys.

Values

module type VALUE = sig ... end

Module type used for specifying custom homogeneous value types in MakeCustomMap. For most purposes, use the provided Value implementation. It sets 'a t = 'a, which is the desired effect (maps can map to any value). This is the case in MakeMap. However, for maps like Hash-consed maps and sets, it can be useful to restrict the type of values in order to implement hash and polyeq functions on values. See the HASHED_VALUE module type for more details.

module Value : VALUE with type 'a t = 'a

Default implementation of VALUE, used in MakeMap.

module type HETEROGENEOUS_VALUE = sig ... end

The module type of values, which can be heterogeneous. This can be used to specify how the type of the value depends on that of the key. If the value doesn't depend on the key type, you can use the provided default implementations HomogeneousValue and WrappedHomogeneousValue.

module HomogeneousValue : HETEROGENEOUS_VALUE with type ('a, 'map) t = 'map

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.

module WrappedHomogeneousValue : + HETEROGENEOUS_VALUE with type ('a, 'map) t = ('a, 'map) snd

Same as HomogeneousValue, but uses a wrapper (unboxed) type instead of direct equality. This avoids a problem in the typechecker with overly eager simplification of aliases. More info on the OCaml discourse post.

module type HASHED_VALUE = sig ... end

VALUE parameter for Hash-consed maps and sets, as hash-consing requires hashing and comparing values.

module type HETEROGENEOUS_HASHED_VALUE = sig ... end

In order to build Hash-consed maps and sets, we need to be able to hash and compare values.

module HashedValue : HASHED_VALUE with type 'a t = 'a

Generic implementation of HASHED_VALUE. Uses 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 HASHED_VALUE.polyeq for details on this.

module HeterogeneousHashedValue : + HETEROGENEOUS_HASHED_VALUE with type ('k, 'm) t = 'm

Generic implementation of HETEROGENEOUS_HASHED_VALUE. Uses 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 HASHED_VALUE.polyeq for details on this.

Functors

This section presents the functors which can be used to build patricia tree maps and sets.

Homogeneous maps and sets

These are homogeneous maps and set, their keys/elements are a single non-generic type, just like the standard library's Map and Set modules.

module MakeMap (Key : KEY) : MAP with type key = Key.t
module MakeSet (Key : KEY) : SET with type elt = Key.t

Heterogeneous maps and sets

Heterogeneous maps are 'map map, which store bindings of 'key key to ('key, 'map) value, where 'key key is a GADT, as we must be able to compare keys of different types together.

Similarly, heterogeneous sets store sets of 'key key.

A set containing different keys, very similar to SET, but with simple type elt being replaced by type constructor 'a elt.

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

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.

Maps and sets with custom nodes

We can also customize the representation and creation of nodes, to gain space or time.

Possibitities include having weak key and/or values, hash-consing, giving unique number to nodes or keeping them in sync with the disk, lazy evaluation and/or caching, adding size information for constant time cardinal functions, etc.

See Some implementations of NODE for the provided implementations of NODE, or create your own.

module MakeCustomMap + (Key : KEY) + (Value : VALUE) + (Node : + NODE + with type 'a key = Key.t + and type ('key, 'map) value = ('key, 'map Value.t) snd) : + MAP_WITH_VALUE + with type key = Key.t + and type 'm value = 'm Value.t + and type 'm t = 'm Node.t

Create a homogeneous map with a custom NODE. Also allows customizing the map values

module MakeCustomSet + (Key : KEY) + (Node : NODE with type 'a key = Key.t and type ('key, 'map) value = unit) : + SET with type elt = Key.t and type 'a BaseMap.t = 'a Node.t

Create a homogeneous set with a custom NODE.

module MakeCustomHeterogeneousMap + (Key : HETEROGENEOUS_KEY) + (Value : HETEROGENEOUS_VALUE) + (Node : + NODE + with type 'a key = 'a Key.t + and type ('key, 'map) value = ('key, 'map) Value.t) : + HETEROGENEOUS_MAP + with type 'a key = 'a Key.t + and type ('k, 'm) value = ('k, 'm) Value.t + and type 'm t = 'm Node.t

Create an heterogeneous map with a custom NODE.

module MakeCustomHeterogeneousSet + (Key : HETEROGENEOUS_KEY) + (NODE : NODE with type 'a key = 'a Key.t and type ('key, 'map) value = unit) : + HETEROGENEOUS_SET + with type 'a elt = 'a Key.t + and type 'a BaseMap.t = 'a NODE.t

Create an heterogeneous set with a custom NODE.

Hash-consed maps and sets

Hash-consed maps and sets uniquely number each of their nodes. Upon creation, they check whether a similar node has been created before, if so they return it, else they return a new node with a new number. With this unique numbering:

All hash-consing functors are generative, since each functor call will create a new hash-table to store the created nodes. Calling a functor twice with same arguments will lead to two numbering systems for identifiers, and thus the types should not be considered compatible.

module MakeHashconsedMap (Key : KEY) (Value : HASHED_VALUE) () : sig ... end

Hash-consed version of MAP. See Hash-consed maps and sets for the differences between hash-consed and non hash-consed maps.

module MakeHashconsedSet (Key : KEY) () : sig ... end

Hash-consed version of SET. See Hash-consed maps and sets for the differences between hash-consed and non hash-consed sets.

module MakeHashconsedHeterogeneousSet + (Key : HETEROGENEOUS_KEY) + () : + sig ... end

Hash-consed version of HETEROGENEOUS_SET. See Hash-consed maps and sets for the differences between hash-consed and non hash-consed sets.

Hash-consed version of HETEROGENEOUS_MAP. See Hash-consed maps and sets for the differences between hash-consed and non hash-consed maps.

Some implementations of NODE

We provide a few different implementations of NODE, they can be used with the MakeCustomMap, MakeCustomSet, MakeCustomHeterogeneousMap and MakeCustomHeterogeneousSet functors.

Basic nodes

module SimpleNode + (Key : sig ... end) + (Value : HETEROGENEOUS_VALUE) : + NODE + with type 'a key = 'a Key.t + and type ('key, 'map) value = ('key, 'map) Value.t

This module is such that 'map t = 'map view. This is the node used in MakeHeterogeneousMap and MakeMap.

module NodeWithId + (Key : sig ... end) + (Value : HETEROGENEOUS_VALUE) : + NODE_WITH_ID + with type 'a key = 'a Key.t + and type ('key, 'map) value = ('key, 'map) Value.t

Here, nodes also contain a unique id, e.g. so that they can be used as keys of maps or hash-tables.

module SetNode + (Key : sig ... end) : + NODE with type 'a key = 'a Key.t and type ('key, 'map) value = unit

An optimized representation for sets, i.e. maps to unit: we do not store a reference to unit (note that you can further optimize when you know the representation of the key). This is the node used in MakeHeterogeneousSet and MakeSet.

Weak nodes

module WeakNode + (Key : sig ... end) + (Value : HETEROGENEOUS_VALUE) : + NODE + with type 'a key = 'a Key.t + and type ('key, 'map) value = ('key, 'map) Value.t

NODE used to implement weak key hashes (the key-binding pair is an Ephemeron, the reference to the key is weak, and if the key is garbage collected, the binding disappears from the map

module WeakSetNode + (Key : sig ... end) : + NODE with type 'a key = 'a Key.t and type ('key, 'map) value = unit

Both a WeakNode and a SetNode, useful to implement Weak sets.

Hashconsed nodes

module HashconsedNode + (Key : HETEROGENEOUS_KEY) + (Value : HETEROGENEOUS_HASHED_VALUE) + () : + HASH_CONSED_NODE + with type 'a key = 'a Key.t + and type ('key, 'map) value = ('key, 'map) Value.t

Gives a unique number to each node like NodeWithId, but also performs hash-consing. So two maps with the same bindings will always be physically equal. See Hash-consed maps and sets for more details on this.

module HashconsedSetNode + (Key : HETEROGENEOUS_KEY) + () : + HASH_CONSED_NODE + with type 'a key = 'a Key.t + and type ('key, 'map) value = unit

Both a HashconsedNode and a SetNode.

diff --git a/v0.10.0/PatriciaTree/module-type-BASE_MAP/index.html b/v0.10.0/PatriciaTree/module-type-BASE_MAP/index.html new file mode 100644 index 0000000..505a71c --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-BASE_MAP/index.html @@ -0,0 +1,69 @@ + +BASE_MAP (patricia-tree.PatriciaTree.BASE_MAP)

Module type PatriciaTree.BASE_MAP

Base map signature: a generic 'b map storing bindings of 'a key to ('a,'b) values. All maps and set are a variation of this type, sometimes with a simplified interface.

include NODE

Types

type 'key key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/module-type-HASHED_VALUE/index.html b/v0.10.0/PatriciaTree/module-type-HASHED_VALUE/index.html new file mode 100644 index 0000000..85fd82e --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-HASHED_VALUE/index.html @@ -0,0 +1,29 @@ + +HASHED_VALUE (patricia-tree.PatriciaTree.HASHED_VALUE)

Module type PatriciaTree.HASHED_VALUE

VALUE parameter for Hash-consed maps and sets, 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 Hashtbl.hash as hash function and physical equality as polyeq.

type 'a t

The type of values for a hash-consed maps.

Unlike VALUE.t, 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

val hash : 'map t -> int

hash v should return an integer hash for the value v. It is used for hash-consing.

Hashing should be fast, avoid mapping too many values to the same integer and compatible with polyeq (equal values must have the same hash: polyeq v1 v2 = true ==> hash v1 = hash v2).

val polyeq : 'a t -> 'b t -> bool

Polymorphic equality on values.

WARNING: if polyeq a b is true, then casting b to the type of a (and a to the type of b) must be type-safe. Eg. if a : t1 t and b : t2 t yield polyeq a b = true, then let a' : t2 t = Obj.magic a and let b' : t1 t = Obj.magic b must be safe.

Examples of safe implementations include:

  • Having a type 'a t which doesn't depend on 'a, in which case casting form 'a t to 'b t is always safe:

    type _ t = foo
    +let cast : type a b. a t -> b t = fun x -> x
    +let polyeq : type a b. a t -> b t -> bool = fun x y -> x = y
  • Using a GADT type and examining its constructors to only return true when the constructors are equal:

    type _ t =
    +    | T_Int : int -> int t
    +    | T_Bool : bool -> bool t
    +let polyeq : type a b. a t -> b t -> bool = fun x y ->
    +    match x, y with
    +    | T_Int i, T_Int j -> i = j (* Here type a = b = int, we can return true *)
    +    | T_Bool i, T_Bool j -> i && j (* same here, but with a = b = bool *)
    +    | _ -> false (* never return true on heterogeneous cases. *)
  • Using physical equality:

    let polyeq a b = a == Obj.magic b

    While this contains an Obj.magic, it is still type safe (OCaml just compares the immediate values) and we can safely cast values from one type to the other if they satisfy this (since they are already physically equal).

    This is the implementation used in HashedValue. Note however that using this function can lead to identifiers no longer being unique across types. They will still be unique and behave as expected within a certain type, but since some values of different types can physically equal, we may have identifer clashes:

    # 97 == Obj.magic 'a';;
    +- : bool = true
    module HMap = MakeHashconsedMap(struct
    +    type t = int
    +    let to_int x = x
    +end)(HashedValue)()
    # let m1 = HMap.singleton 5 97;;
    +val m1 : int HMap.t = <abstr>
    +# let m2 = HMap.singleton 5 'a';;
    +val m2 : char HMap.t = <abstr>
    +# HMap.to_int m1 = HMap.to_int m2;;
    +- : bool = true

    This can cause problems if you wish to use identifiers of different map types together:

    type any = Any : 'a HMap.t -> any
    +module MapOfMaps = MakeMap(struct
    +  type t = any
    +  let to_int (Any x) = HMap.to_int x
    +end)

    Using this can lead to unexpected behaviors: in the following m3 has cardinal 1, the m1->"foo" binding has been overwritten

    # let m3 = MapOfMaps.of_list [ (Any m1, "foo"); (Any m2, "bar") ]
    +val m3 : string MapOfMaps.t = <abstr>
    +# MapOfMaps.to_list m3
    +- : (any * string) list = [(Any <abstr>, "bar")]

    This issue does not happen with the two previous variants, since they both only return true on the same types.

diff --git a/v0.10.0/PatriciaTree/module-type-HASH_CONSED_NODE/index.html b/v0.10.0/PatriciaTree/module-type-HASH_CONSED_NODE/index.html new file mode 100644 index 0000000..ab8f924 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-HASH_CONSED_NODE/index.html @@ -0,0 +1,9 @@ + +HASH_CONSED_NODE (patricia-tree.PatriciaTree.HASH_CONSED_NODE)

Module type PatriciaTree.HASH_CONSED_NODE

Hash-consed nodes also associate a unique number to each node, 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.

See Hash-consed maps and sets for a details on strengths and limits of hash-consing.

include NODE

Types

type 'key key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

val to_int : 'a t -> int

Returns a unique number for each map, the hash-consed identifier of the map. 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 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 HASHED_VALUE.polyeq for details.

val equal : 'a t -> 'a t -> bool

Constant time equality using the 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 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 node identifiers. This order is fully arbitrary, but it is total and can be used to sort nodes. It is based on node ids which depend on the order in which the nodes where created (older nodes having smaller ids).

One useful property of this order is that child nodes will always have a smaller identifier than their parents.

diff --git a/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_HASHED_VALUE/index.html b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_HASHED_VALUE/index.html new file mode 100644 index 0000000..1738e72 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_HASHED_VALUE/index.html @@ -0,0 +1,13 @@ + +HETEROGENEOUS_HASHED_VALUE (patricia-tree.PatriciaTree.HETEROGENEOUS_HASHED_VALUE)

Module type PatriciaTree.HETEROGENEOUS_HASHED_VALUE

In order to build Hash-consed maps and sets, we need to be able to hash and compare values.

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 Hashtbl.hash as hash function and physical equality as polyeq.

type ('key, 'map) t

The type of values for a hash-consed maps.

Unlike HETEROGENEOUS_VALUE.t, 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

val hash : ('key, 'map) t -> int

hash v should return an integer hash for the value v. It is used for hash-consing.

Hashing should be fast, avoid mapping too many values to the same integer and compatible with polyeq (equal values must have the same hash: polyeq v1 v2 = true ==> hash v1 = hash v2).

val polyeq : ('key, 'map_a) t -> ('key, 'map_b) t -> bool

Polymorphic equality on values.

WARNING: if polyeq a b is true, then casting b to the type of a (and a to the type of b) must be type-safe. Eg. if a : (k, t1) t and b : (k, t2) t yield polyeq a b = true, then let a' : (k,t2) t = Obj.magic a and let b' : (k,t1) t = Obj.magic b must be safe.

Examples of safe implementations include:

  • Having a type ('key, 'map) t which doesn't depend on 'map (i can depend on 'key), in which case casting form ('key, 'a) t to ('key, 'b) t is always safe:

    type ('k, _) t = 'k list
    +let cast : type a b. ('k, a) t -> ('k, b) t = fun x -> x
    +let polyeq : type a b. ('k, a) t -> ('k, b) t -> bool = fun x y -> x = y
  • Using a GADT type and examining its constructors to only return true when the constructors are equal:

    type (_, _) t =
    +    | T_Int : int -> (unit, int) t
    +    | T_Bool : bool -> (unit, bool) t
    +let polyeq : type k a b. (k, a) t -> (k, b) t -> bool = fun x y ->
    +    match x, y with
    +    | T_Int i, T_Int j -> i = j (* Here type a = b = int, we can return true *)
    +    | T_Bool i, T_Bool j -> i && j (* same here, but with a = b = bool *)
    +    | _ -> false (* never return true on heterogeneous cases. *)
  • Using physical equality:

    let polyeq a b = a == Obj.magic b

    While this contains an Obj.magic, it is still type safe (OCaml just compares the immediate values) and we can safely cast values from one type to the other if they satisfy this (since they are already physically equal).

    This is the implementation used in HeterogeneousHashedValue. Note however that using this function can lead to identifiers no longer being unique across types. See HASHED_VALUE.polyeq for more information on this.

diff --git a/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_KEY/index.html b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_KEY/index.html new file mode 100644 index 0000000..9f4b8b5 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_KEY/index.html @@ -0,0 +1,4 @@ + +HETEROGENEOUS_KEY (patricia-tree.PatriciaTree.HETEROGENEOUS_KEY)

Module type PatriciaTree.HETEROGENEOUS_KEY

The signature of heterogeneous keys.

type 'key t

The type of generic/heterogeneous keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : 'key t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

val polyeq : 'a t -> 'b t -> ('a, 'b) cmp

Polymorphic equality function used to compare our keys. It should satisfy (to_int a) = (to_int b) ==> polyeq a b = Eq, and be fast.

diff --git a/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_MAP/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_MAP/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..2e9c1e5 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_MAP/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.HETEROGENEOUS_MAP.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_MAP/WithForeign/index.html b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_MAP/WithForeign/index.html new file mode 100644 index 0000000..520332b --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_MAP/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.HETEROGENEOUS_MAP.WithForeign)

Module HETEROGENEOUS_MAP.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_MAP/index.html b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_MAP/index.html new file mode 100644 index 0000000..5ee0b96 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_MAP/index.html @@ -0,0 +1,69 @@ + +HETEROGENEOUS_MAP (patricia-tree.PatriciaTree.HETEROGENEOUS_MAP)

Module type PatriciaTree.HETEROGENEOUS_MAP

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 MAP are:

include BASE_MAP
include NODE

Types

type 'key key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/BaseMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/BaseMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..5906348 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/BaseMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.HETEROGENEOUS_SET.BaseMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/BaseMap/WithForeign/index.html b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/BaseMap/WithForeign/index.html new file mode 100644 index 0000000..afb49b2 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/BaseMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.HETEROGENEOUS_SET.BaseMap.WithForeign)

Module BaseMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/BaseMap/index.html b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/BaseMap/index.html new file mode 100644 index 0000000..f2b551e --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/BaseMap/index.html @@ -0,0 +1,69 @@ + +BaseMap (patricia-tree.PatriciaTree.HETEROGENEOUS_SET.BaseMap)

Module HETEROGENEOUS_SET.BaseMap

Underlying basemap, for cross map/set operations

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 MAP are:

include BASE_MAP with type 'a key = 'a elt with type (_, _) value = unit
include NODE with type 'a key = 'a elt with type (_, _) value = unit

Types

type 'a key = 'a elt

The type of keys.

type (_, _) value = unit

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/index.html b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/index.html new file mode 100644 index 0000000..f601248 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_SET/index.html @@ -0,0 +1,10 @@ + +HETEROGENEOUS_SET (patricia-tree.PatriciaTree.HETEROGENEOUS_SET)

Module type PatriciaTree.HETEROGENEOUS_SET

A set containing different keys, very similar to SET, but with simple type elt being replaced by type constructor 'a elt.

The main changes from SET are:

type 'a elt

Elements of the set

module BaseMap : + HETEROGENEOUS_MAP with type 'a key = 'a elt and type (_, _) value = unit

Underlying basemap, for cross map/set operations

type t = unit BaseMap.t

The type of our set

type 'a key = 'a elt

Alias for elements, for compatibility with other PatriciaTrees

type any_elt =
  1. | Any : 'a elt -> any_elt

Existential wrapper for set elements.

Basic functions

val empty : t

The empty set

val is_empty : t -> bool

is_empty st is true if st contains no elements, false otherwise

val mem : 'a elt -> t -> bool

mem elt set is true if elt is contained in set, O(log(n)) complexity.

val add : 'a elt -> t -> t

add elt set adds element elt to the set. Preserves physical equality if elt was already present. O(log(n)) complexity.

val singleton : 'a elt -> t

singleton elt returns a set containing a single element: elt

val cardinal : t -> int

the size of the set (number of elements), O(n) complexity.

val is_singleton : t -> any_elt option

is_singleton set is Some (Any elt) if set is singleton elt and None otherwise.

val remove : 'a elt -> t -> t

remove elt set returns a set containing all elements of set except elt. Returns a value physically equal to set if elt is not present.

val unsigned_min_elt : t -> any_elt

The minimal element if non empty, according to the unsigned order on elements.

  • raises Not_found
val unsigned_max_elt : t -> any_elt

The maximal element if non empty, according to the unsigned order on elements.

  • raises Not_found
val pop_unsigned_minimum : t -> (any_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 order on elements.

val pop_unsigned_maximum : t -> (any_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 order on elements.

Functions on pairs of sets

val union : t -> t -> t

union a b is the set union of a and b, i.e. the set containing all elements that are either in a or b.

val inter : t -> t -> t

inter a b is the set intersection of a and b, i.e. the set containing all elements that are in both a or b.

val disjoint : t -> t -> bool

disjoint a b is true if a and b have no elements in common.

val equal : t -> t -> bool

equal a b is true if a and b contain the same elements.

val subset : t -> t -> bool

subset a b is true if all elements of a are also in b.

val split : 'a 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 order on elements.

Iterators

type polyiter = {
  1. f : 'a. 'a elt -> unit;
}
val iter : polyiter -> t -> unit

iter f set calls f.f on all elements of set, in the unsigned order of KEY.to_int.

type polypredicate = {
  1. f : 'a. 'a elt -> bool;
}
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 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 order of KEY.to_int.

type 'acc polyfold = {
  1. f : 'a. 'a elt -> 'acc -> 'acc;
}
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 order of KEY.to_int

type polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a elt -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + polypretty -> + Stdlib.Format.formatter -> + t -> + unit

Pretty prints the set, pp_sep is called once between each element, it defaults to Format.pp_print_cut

Conversion functions

val to_seq : t -> any_elt Stdlib.Seq.t

to_seq st iterates the whole set, in increasing unsigned order of KEY.to_int

val to_rev_seq : t -> any_elt Stdlib.Seq.t

to_rev_seq st iterates the whole set, in decreasing unsigned order of KEY.to_int

val add_seq : any_elt Stdlib.Seq.t -> t -> t

add_seq s st adds all elements of the sequence s to st in order.

val of_seq : any_elt Stdlib.Seq.t -> t

of_seq s creates a new set from the elements of s.

val of_list : any_elt list -> t

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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_VALUE/index.html b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_VALUE/index.html new file mode 100644 index 0000000..0aa3215 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-HETEROGENEOUS_VALUE/index.html @@ -0,0 +1,4 @@ + +HETEROGENEOUS_VALUE (patricia-tree.PatriciaTree.HETEROGENEOUS_VALUE)

Module type PatriciaTree.HETEROGENEOUS_VALUE

The module type of values, which can be heterogeneous. This can be used to specify how the type of the value depends on that of the key. If the value doesn't depend on the key type, you can use the provided default implementations HomogeneousValue and WrappedHomogeneousValue.

type ('key, 'map) t

The type of values. A 'map map maps 'key key to ('key, 'map) value. Can be mutable if desired, unless it is being used in Hash-consed maps and sets.

diff --git a/v0.10.0/PatriciaTree/module-type-KEY/index.html b/v0.10.0/PatriciaTree/module-type-KEY/index.html new file mode 100644 index 0000000..e9dc349 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-KEY/index.html @@ -0,0 +1,4 @@ + +KEY (patricia-tree.PatriciaTree.KEY)

Module type PatriciaTree.KEY

The signature of homogeneous keys (non-generic, unparameterized keys).

type t

The type of keys.

It is recommended to use immutable keys. If keys are mutable, any mutations to keys must preserve to_int. Failing to do so will break the patricia trees' invariants.

val to_int : t -> int

A unique identifier for values of the type. Usually, we use a fresh counter that is increased to give a unique id to each object. Correctness of the operations requires that different values in a tree correspond to different integers.

Must be injective, and ideally fast. hash-consing keys is a good way to generate such unique identifiers.

Note that since Patricia Trees use unsigned order, negative keys are seen as bigger than positive keys. Be wary of this when using negative keys combined with functions like unsigned_max_binding and pop_unsigned_maximum.

diff --git a/v0.10.0/PatriciaTree/module-type-MAP/BaseMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/module-type-MAP/BaseMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..ba2e749 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-MAP/BaseMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MAP.BaseMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/module-type-MAP/BaseMap/WithForeign/index.html b/v0.10.0/PatriciaTree/module-type-MAP/BaseMap/WithForeign/index.html new file mode 100644 index 0000000..aee5a72 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-MAP/BaseMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.MAP.BaseMap.WithForeign)

Module BaseMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/module-type-MAP/BaseMap/index.html b/v0.10.0/PatriciaTree/module-type-MAP/BaseMap/index.html new file mode 100644 index 0000000..047d42c --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-MAP/BaseMap/index.html @@ -0,0 +1,75 @@ + +BaseMap (patricia-tree.PatriciaTree.MAP.BaseMap)

Module MAP.BaseMap

Underlying basemap, for cross map/set operations

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 MAP are:

include BASE_MAP + with type 'a t = 'a t + with type _ key = key + with type ('a, 'b) value = ('a, 'b value) snd
include NODE + with type 'a t = 'a t + with type _ key = key + with type ('a, 'b) value = ('a, 'b value) snd

Types

type _ key = key

The type of keys.

type ('a, 'b) value = ('a, 'b value) snd

The type of value, which depends on the type of the key and the type of the map.

type 'a t = 'a t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/module-type-MAP/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/module-type-MAP/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..dea5906 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-MAP/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MAP.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type _ key = key

Types

type _ key = key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/module-type-MAP/WithForeign/index.html b/v0.10.0/PatriciaTree/module-type-MAP/WithForeign/index.html new file mode 100644 index 0000000..99bc2c4 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-MAP/WithForeign/index.html @@ -0,0 +1,19 @@ + +WithForeign (patricia-tree.PatriciaTree.MAP.WithForeign)

Module MAP.WithForeign

Combination with other kinds of maps. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type _ key = key

Signature

type ('b, 'c) polyfilter_map_foreign = {
  1. f : 'a. key -> ('a, 'b) Map2.value -> 'c value option;
}
val filter_map_no_share : ('b, 'c) polyfilter_map_foreign -> 'b Map2.t -> 'c t

Like filter_map_no_share, but takes another map.

type ('value, 'map2) polyinter_foreign = {
  1. f : 'a. 'a Map2.key -> 'value value -> ('a, 'map2) Map2.value -> 'value value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like nonidempotent_inter, but takes another map as an argument.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. key -> + 'map1 value option -> + ('a, 'map2) Map2.value -> + 'map1 value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update (but more efficient) update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. key -> 'map1 value -> ('a, 'map2) Map2.value -> 'map1 value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/module-type-MAP/index.html b/v0.10.0/PatriciaTree/module-type-MAP/index.html new file mode 100644 index 0000000..9f02a76 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-MAP/index.html @@ -0,0 +1,57 @@ + +MAP (patricia-tree.PatriciaTree.MAP)

Module type PatriciaTree.MAP

The signature for maps with a single type for keys and values, a 'a map binds key to 'a. Most of this interface should be shared with Stdlib.Map.S.

type key

The type of keys.

type 'a t

A map from key to values of type 'a value.

type 'a value = 'a

Type for values, this is a divergence from Stdlib's 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.

  • since v0.10.0
module BaseMap : + HETEROGENEOUS_MAP + with type 'a t = 'a t + and type _ key = key + and type ('a, 'b) value = ('a, 'b value) snd

Underlying basemap, for cross map/set operations

Basic functions

val empty : 'a t

The empty map.

val is_empty : 'a t -> bool

Test if a map is empty; O(1) complexity.

val unsigned_min_binding : 'a t -> key * 'a value

Returns the (key,value) pair where Key.to_int key is minimal (in the unsigned representation of integers); O(log n) complexity.

  • raises Not_found

    if the map is empty.

val unsigned_max_binding : 'a t -> key * 'a value

Returns the (key,value) pair where Key.to_int key is maximal (in the unsigned representation of integers); O(log n) complexity.

  • raises Not_found

    if the map is empty.

val singleton : key -> 'a value -> 'a t

singleton key value creates a map with a single binding, O(1) complexity.

val cardinal : 'a t -> int

The size of the map. O(n) complexity.

val is_singleton : 'a t -> (key * 'a value) option

is_singleton m is Some (k,v) iff m is singleton k v.

val find : key -> 'a t -> 'a value

Return an element in the map, or raise Not_found, O(log(n)) complexity.

val find_opt : key -> 'a t -> 'a value option

Return an element in the map, or None, O(log(n)) complexity.

val mem : key -> 'a t -> bool

mem key map returns true if and only if key is bound in map. O(log(n)) complexity.

val remove : key -> 'a t -> 'a t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 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 takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : key -> ('a value option -> 'a value option) -> 'a t -> 'a t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : key -> 'a value -> 'a t -> 'a t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : key -> 'a t -> 'a t * 'a value option * 'a t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Uses the 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 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 order of KEY.to_int.

val fold_on_nonequal_inter : + (key -> 'a value -> 'a value -> 'acc -> 'acc) -> + 'a t -> + 'a t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 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

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the 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 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 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 the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

val map : ('a value -> 'a value) -> 'a t -> 'a t

map f m returns a map where the value bound to each key is replaced by f value. The subtrees for which the returned 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 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 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 replaced by f key value. The subtrees for which the returned 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 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 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 key is removed (if f key value returns None), or is replaced by v ((if f key value returns Some v). The subtrees for which the returned value is physically the same (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 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 order of KEY.to_int.

Operations on pairs of maps

The following functions combine two maps. It is key for the performance, when we have large maps who share common subtrees, not to visit the nodes in these subtrees. Hence, we have specialized versions of these functions that assume properties of the function parameter (reflexive relation, idempotent operation, etc.)

When we cannot enjoy these properties, our functions explicitly say so (with a nonreflexive or nonidempotent prefix). The names are a bit long, but having these names avoids using an ineffective code by default, by forcing to know and choose between the fast and slow version.

It is also important to not visit a subtree when there merging this subtree with Empty; hence we provide union and inter operations.

val reflexive_same_domain_for_all2 : + (key -> 'a value -> 'a value -> bool) -> + 'a t -> + 'a t -> + bool

reflexive_same_domain_for_all2 f map1 map2 returns true if map1 and map2 have the same keys, and f key value1 value2 returns true for each mapping pair of keys. We assume that f is reflexive (i.e. f key value value returns true) to avoid visiting physically equal subtrees of map1 and map2. The complexity is O(log(n)*Delta) where Delta is the number of different keys between map1 and map2.

val nonreflexive_same_domain_for_all2 : + (key -> 'a value -> 'b value -> bool) -> + 'a t -> + 'b t -> + bool

nonreflexive_same_domain_for_all2 f map1 map2 returns true if map1 and map2 have the same keys, and f key value1 value2 returns true for each mapping pair of keys. The complexity is O(min(|map1|,|map2|)).

val reflexive_subset_domain_for_all2 : + (key -> 'a value -> 'a value -> bool) -> + 'a t -> + 'a t -> + bool

reflexive_subset_domain_for_all2 f map1 map2 returns true if all the keys of map1 also are in map2, and f key (find map1 + key) (find map2 key) returns true when both keys are present in the map. We assume that f is reflexive (i.e. f key value + value returns true) to avoid visiting physically equal subtrees of map1 and map2. The complexity is O(log(n)*Delta) where Delta is the number of different keys between map1 and map2.

val idempotent_union : + (key -> 'a value -> 'a value -> 'a value) -> + 'a t -> + 'a t -> + 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. We assume that f is idempotent (i.e. f key value value == value) to avoid visiting physically equal subtrees of map1 and map2, and also to 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 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

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. We assume that f is idempotent (i.e. f key value value == value) to avoid visiting physically equal subtrees of map1 and map2, and also to 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 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

nonidempotent_inter_no_share f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. f does not 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 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

idempotent_inter_filter f m1 m2 is like idempotent_inter (assuming idempotence, using and preserving physically equal subtrees), but it also removes the key->value bindings for which f returns None.

val slow_merge : + (key -> 'a value option -> 'b value option -> 'c value option) -> + 'a t -> + 'b t -> + 'c t

slow_merge f m1 m2 returns a map whose keys are a subset of the keys of m1 and m2. The f function is used to combine keys, similarly to the Map.merge function. This funcion has to traverse all the bindings in m1 and m2; its complexity is O(|m1|+|m2|). Use one of faster functions above if you can.

val disjoint : 'a t -> 'a t -> bool
module WithForeign (Map2 : BASE_MAP with type _ key = key) : sig ... end

Combination with other kinds of maps. Map2 must use the same KEY.to_int function.

val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + (Stdlib.Format.formatter -> key -> 'a value -> unit) -> + Stdlib.Format.formatter -> + 'a t -> + unit

Pretty prints all bindings of the map. pp_sep is called once between each binding pair and defaults to Format.pp_print_cut.

Conversion functions

val to_seq : 'a t -> (key * 'a value) Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> (key * 'a value) Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : (key * 'a value) Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : (key * 'a value) Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : (key * 'a value) list -> 'a t

of_list l creates a new map from the bindings of l. If a key is bound multiple times in l, the latest binding is kept

val to_list : 'a t -> (key * 'a value) list

to_list m returns the bindings of m as a list, in increasing unsigned order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/BaseMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/BaseMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..08094eb --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/BaseMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MAP_WITH_VALUE.BaseMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/BaseMap/WithForeign/index.html b/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/BaseMap/WithForeign/index.html new file mode 100644 index 0000000..3ead516 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/BaseMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.MAP_WITH_VALUE.BaseMap.WithForeign)

Module BaseMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/BaseMap/index.html b/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/BaseMap/index.html new file mode 100644 index 0000000..aa8f7f4 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/BaseMap/index.html @@ -0,0 +1,75 @@ + +BaseMap (patricia-tree.PatriciaTree.MAP_WITH_VALUE.BaseMap)

Module MAP_WITH_VALUE.BaseMap

Underlying basemap, for cross map/set operations

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 MAP are:

include BASE_MAP + with type 'a t = 'a t + with type _ key = key + with type ('a, 'b) value = ('a, 'b value) snd
include NODE + with type 'a t = 'a t + with type _ key = key + with type ('a, 'b) value = ('a, 'b value) snd

Types

type _ key = key

The type of keys.

type ('a, 'b) value = ('a, 'b value) snd

The type of value, which depends on the type of the key and the type of the map.

type 'a t = 'a t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..2e26422 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.MAP_WITH_VALUE.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type _ key = key

Types

type _ key = key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/WithForeign/index.html b/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/WithForeign/index.html new file mode 100644 index 0000000..c3aa5d6 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/WithForeign/index.html @@ -0,0 +1,19 @@ + +WithForeign (patricia-tree.PatriciaTree.MAP_WITH_VALUE.WithForeign)

Module MAP_WITH_VALUE.WithForeign

Combination with other kinds of maps. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type _ key = key

Signature

type ('b, 'c) polyfilter_map_foreign = {
  1. f : 'a. key -> ('a, 'b) Map2.value -> 'c value option;
}
val filter_map_no_share : ('b, 'c) polyfilter_map_foreign -> 'b Map2.t -> 'c t

Like filter_map_no_share, but takes another map.

type ('value, 'map2) polyinter_foreign = {
  1. f : 'a. 'a Map2.key -> 'value value -> ('a, 'map2) Map2.value -> 'value value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like nonidempotent_inter, but takes another map as an argument.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. key -> + 'map1 value option -> + ('a, 'map2) Map2.value -> + 'map1 value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update (but more efficient) update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. key -> 'map1 value -> ('a, 'map2) Map2.value -> 'map1 value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/index.html b/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/index.html new file mode 100644 index 0000000..a9a6aec --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-MAP_WITH_VALUE/index.html @@ -0,0 +1,57 @@ + +MAP_WITH_VALUE (patricia-tree.PatriciaTree.MAP_WITH_VALUE)

Module type PatriciaTree.MAP_WITH_VALUE

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 MAP, which just binds to 'a. It is used for maps that need to restrict their value type, namely Hash-consed maps and sets.

type key

The type of keys.

type 'a t

A map from key to values of type 'a value.

type 'a value

Type for values, this is a divergence from Stdlib's 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.

  • since v0.10.0
module BaseMap : + HETEROGENEOUS_MAP + with type 'a t = 'a t + and type _ key = key + and type ('a, 'b) value = ('a, 'b value) snd

Underlying basemap, for cross map/set operations

Basic functions

val empty : 'a t

The empty map.

val is_empty : 'a t -> bool

Test if a map is empty; O(1) complexity.

val unsigned_min_binding : 'a t -> key * 'a value

Returns the (key,value) pair where Key.to_int key is minimal (in the unsigned representation of integers); O(log n) complexity.

  • raises Not_found

    if the map is empty.

val unsigned_max_binding : 'a t -> key * 'a value

Returns the (key,value) pair where Key.to_int key is maximal (in the unsigned representation of integers); O(log n) complexity.

  • raises Not_found

    if the map is empty.

val singleton : key -> 'a value -> 'a t

singleton key value creates a map with a single binding, O(1) complexity.

val cardinal : 'a t -> int

The size of the map. O(n) complexity.

val is_singleton : 'a t -> (key * 'a value) option

is_singleton m is Some (k,v) iff m is singleton k v.

val find : key -> 'a t -> 'a value

Return an element in the map, or raise Not_found, O(log(n)) complexity.

val find_opt : key -> 'a t -> 'a value option

Return an element in the map, or None, O(log(n)) complexity.

val mem : key -> 'a t -> bool

mem key map returns true if and only if key is bound in map. O(log(n)) complexity.

val remove : key -> 'a t -> 'a t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 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 takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : key -> ('a value option -> 'a value option) -> 'a t -> 'a t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : key -> 'a value -> 'a t -> 'a t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : key -> 'a t -> 'a t * 'a value option * 'a t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Uses the 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 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 order of KEY.to_int.

val fold_on_nonequal_inter : + (key -> 'a value -> 'a value -> 'acc -> 'acc) -> + 'a t -> + 'a t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 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

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the 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 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 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 the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

val map : ('a value -> 'a value) -> 'a t -> 'a t

map f m returns a map where the value bound to each key is replaced by f value. The subtrees for which the returned 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 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 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 replaced by f key value. The subtrees for which the returned 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 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 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 key is removed (if f key value returns None), or is replaced by v ((if f key value returns Some v). The subtrees for which the returned value is physically the same (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 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 order of KEY.to_int.

Operations on pairs of maps

The following functions combine two maps. It is key for the performance, when we have large maps who share common subtrees, not to visit the nodes in these subtrees. Hence, we have specialized versions of these functions that assume properties of the function parameter (reflexive relation, idempotent operation, etc.)

When we cannot enjoy these properties, our functions explicitly say so (with a nonreflexive or nonidempotent prefix). The names are a bit long, but having these names avoids using an ineffective code by default, by forcing to know and choose between the fast and slow version.

It is also important to not visit a subtree when there merging this subtree with Empty; hence we provide union and inter operations.

val reflexive_same_domain_for_all2 : + (key -> 'a value -> 'a value -> bool) -> + 'a t -> + 'a t -> + bool

reflexive_same_domain_for_all2 f map1 map2 returns true if map1 and map2 have the same keys, and f key value1 value2 returns true for each mapping pair of keys. We assume that f is reflexive (i.e. f key value value returns true) to avoid visiting physically equal subtrees of map1 and map2. The complexity is O(log(n)*Delta) where Delta is the number of different keys between map1 and map2.

val nonreflexive_same_domain_for_all2 : + (key -> 'a value -> 'b value -> bool) -> + 'a t -> + 'b t -> + bool

nonreflexive_same_domain_for_all2 f map1 map2 returns true if map1 and map2 have the same keys, and f key value1 value2 returns true for each mapping pair of keys. The complexity is O(min(|map1|,|map2|)).

val reflexive_subset_domain_for_all2 : + (key -> 'a value -> 'a value -> bool) -> + 'a t -> + 'a t -> + bool

reflexive_subset_domain_for_all2 f map1 map2 returns true if all the keys of map1 also are in map2, and f key (find map1 + key) (find map2 key) returns true when both keys are present in the map. We assume that f is reflexive (i.e. f key value + value returns true) to avoid visiting physically equal subtrees of map1 and map2. The complexity is O(log(n)*Delta) where Delta is the number of different keys between map1 and map2.

val idempotent_union : + (key -> 'a value -> 'a value -> 'a value) -> + 'a t -> + 'a t -> + 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. We assume that f is idempotent (i.e. f key value value == value) to avoid visiting physically equal subtrees of map1 and map2, and also to 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 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

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. We assume that f is idempotent (i.e. f key value value == value) to avoid visiting physically equal subtrees of map1 and map2, and also to 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 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

nonidempotent_inter_no_share f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f is used to combine the values a key is mapped in both maps. f does not 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 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

idempotent_inter_filter f m1 m2 is like idempotent_inter (assuming idempotence, using and preserving physically equal subtrees), but it also removes the key->value bindings for which f returns None.

val slow_merge : + (key -> 'a value option -> 'b value option -> 'c value option) -> + 'a t -> + 'b t -> + 'c t

slow_merge f m1 m2 returns a map whose keys are a subset of the keys of m1 and m2. The f function is used to combine keys, similarly to the Map.merge function. This funcion has to traverse all the bindings in m1 and m2; its complexity is O(|m1|+|m2|). Use one of faster functions above if you can.

val disjoint : 'a t -> 'a t -> bool
module WithForeign (Map2 : BASE_MAP with type _ key = key) : sig ... end

Combination with other kinds of maps. Map2 must use the same KEY.to_int function.

val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + (Stdlib.Format.formatter -> key -> 'a value -> unit) -> + Stdlib.Format.formatter -> + 'a t -> + unit

Pretty prints all bindings of the map. pp_sep is called once between each binding pair and defaults to Format.pp_print_cut.

Conversion functions

val to_seq : 'a t -> (key * 'a value) Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> (key * 'a value) Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : (key * 'a value) Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : (key * 'a value) Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : (key * 'a value) list -> 'a t

of_list l creates a new map from the bindings of l. If a key is bound multiple times in l, the latest binding is kept

val to_list : 'a t -> (key * 'a value) list

to_list m returns the bindings of m as a list, in increasing unsigned order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/module-type-NODE/index.html b/v0.10.0/PatriciaTree/module-type-NODE/index.html new file mode 100644 index 0000000..54f0431 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-NODE/index.html @@ -0,0 +1,9 @@ + +NODE (patricia-tree.PatriciaTree.NODE)

Module type PatriciaTree.NODE

This module explains how a node is stored in memory, with functions to create and view nodes.

We use a uniform type 'map view to pattern match on maps and sets The actual types 'map t can be a bit different from 'map view to allow for more efficient representations, but view should be a constant time operation for quick conversions.

Types

type 'key key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

diff --git a/v0.10.0/PatriciaTree/module-type-NODE_WITH_ID/index.html b/v0.10.0/PatriciaTree/module-type-NODE_WITH_ID/index.html new file mode 100644 index 0000000..7ac0064 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-NODE_WITH_ID/index.html @@ -0,0 +1,9 @@ + +NODE_WITH_ID (patricia-tree.PatriciaTree.NODE_WITH_ID)

Module type PatriciaTree.NODE_WITH_ID

Associate a unique number to each node, so they can be used as keys in sets or maps.

include NODE

Types

type 'key key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

val to_int : 'a t -> int

Unique number for each node.

This is not hash-consing. Equal nodes created separately will have different identifiers. On the flip side, nodes with equal identifiers will always be physically equal.

diff --git a/v0.10.0/PatriciaTree/module-type-SET/BaseMap/WithForeign/argument-1-Map2/index.html b/v0.10.0/PatriciaTree/module-type-SET/BaseMap/WithForeign/argument-1-Map2/index.html new file mode 100644 index 0000000..90005b8 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-SET/BaseMap/WithForeign/argument-1-Map2/index.html @@ -0,0 +1,69 @@ + +Map2 (patricia-tree.PatriciaTree.SET.BaseMap.WithForeign.Map2)

Parameter WithForeign.Map2

include NODE with type 'a key = 'a key

Types

type 'a key = 'a key

The type of keys.

type ('key, 'map) value

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/module-type-SET/BaseMap/WithForeign/index.html b/v0.10.0/PatriciaTree/module-type-SET/BaseMap/WithForeign/index.html new file mode 100644 index 0000000..b38d243 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-SET/BaseMap/WithForeign/index.html @@ -0,0 +1,28 @@ + +WithForeign (patricia-tree.PatriciaTree.SET.BaseMap.WithForeign)

Module BaseMap.WithForeign

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

Parameters

module Map2 : BASE_MAP with type 'a key = 'a key

Signature

type ('map1, 'map2) polyinter_foreign = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value;
}
val nonidempotent_inter : + ('a, 'b) polyinter_foreign -> + 'a t -> + 'b Map2.t -> + 'a t

Like BASE_MAP.idempotent_inter. Tries to preserve physical equality on the first argument when possible.

type ('map2, 'map1) polyfilter_map_foreign = {
  1. f : 'a. 'a key -> ('a, 'map2) Map2.value -> ('a, 'map1) value option;
}
val filter_map_no_share : + ('map2, 'map1) polyfilter_map_foreign -> + 'map2 Map2.t -> + 'map1 t

Like BASE_MAP.filter_map_no_share, but allows to transform a foreigh map into the current one.

type ('map1, 'map2) polyupdate_multiple = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple -> + 'a t -> + 'a t

This is equivalent to multiple calls to update, but more efficient. update_multiple_from_foreign m_from f m_to is the same as calling update k {f=fun v_to -> f.f k v_to v_from} m_to on all bindings (k, v_from) of m_from, 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 order of KEY.to_int. O(size(m_from) + size(m_to)) complexity.

type ('map1, 'map2) polyupdate_multiple_inter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) Map2.value -> + ('a, 'map1) value option;
}
val update_multiple_from_inter_with_foreign : + 'b Map2.t -> + ('a, 'b) polyupdate_multiple_inter -> + 'a t -> + 'a t

update_multiple_from_inter_with_foreign m_from f m_to is the same as update_multiple_from_foreign, except that instead of updating for all keys in m_from, it only updates for keys that are both in m_from and m_to.

diff --git a/v0.10.0/PatriciaTree/module-type-SET/BaseMap/index.html b/v0.10.0/PatriciaTree/module-type-SET/BaseMap/index.html new file mode 100644 index 0000000..8a5ccbf --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-SET/BaseMap/index.html @@ -0,0 +1,69 @@ + +BaseMap (patricia-tree.PatriciaTree.SET.BaseMap)

Module SET.BaseMap

Underlying basemap, for cross map/set operations

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 MAP are:

include BASE_MAP with type _ key = elt with type (_, _) value = unit
include NODE with type _ key = elt with type (_, _) value = unit

Types

type _ key = elt

The type of keys.

type (_, _) value = unit

The type of value, which depends on the type of the key and the type of the map.

type 'map t

The type of the map, which is parameterized by a type.

Constructors: build values

val empty : 'map t

The empty map

val leaf : 'key key -> ('key, 'map) value -> 'map t

A singleton leaf, similar to BASE_MAP.singleton

val branch : + prefix:intkey -> + branching_bit:mask -> + tree0:'map t -> + tree1:'map t -> + 'map t

A branch node. This shouldn't be called externally unless you know what you're doing! Doing so could easily break the data structure's invariants.

When called, it assumes that:

  • Neither tree0 nor tree1 should be empty.
  • branching_bit should have a single bit set
  • prefix should be normalized (bits below branching_bit set to zero)
  • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
  • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).

Destructors: access the value

type 'map view = private
  1. | Empty : 'map view
    (*

    Can happen only at the toplevel: there is no empty interior node.

    *)
  2. | Branch : {
    1. prefix : intkey;
    2. branching_bit : mask;
    3. tree0 : 'map t;
    4. tree1 : 'map t;
    } -> 'map view
    (*

    Same constraints as branch:

    • branching_bit contains only one bit set; the corresponding mask is (branching_bit - 1).
    • prefix is normalized: the bits below the branching_bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).
    • All elements of tree0 should have their to_int start by prefix followed by 0 at position branching_bit).
    • All elements of tree1 should have their to_int start by prefix followed by 0 at position branching_bit).
    *)
  3. | Leaf : {
    1. key : 'key key;
    2. value : ('key, 'map) value;
    } -> 'map view
    (*

    A key -> value mapping.

    *)

This makes the map nodes accessible to the pattern matching algorithm; this corresponds 1:1 to the SimpleNode implementation. This just needs to be copy-and-pasted for every node type.

val is_empty : 'map t -> bool

Check if the map is empty. Should be constant time.

val view : 'a t -> 'a view

Convert the map to a view. Should be constant time.

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair

Existential wrapper for the 'a parameter in a 'a key, ('a,'map) value pair

Basic functions

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 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 order on KEY.to_int.

  • raises Not_found

    if the map is empty

val singleton : 'a key -> ('a, 'b) value -> 'b t

Create a map with a single binding.

val cardinal : 'a t -> int

The size of the map, O(n) complexity

val is_singleton : 'a t -> 'a key_value_pair option

is_singleton m returns Some(KeyValue(k,v)) if and only if m contains a unique binding k->v.

val find : 'key key -> 'map t -> ('key, 'map) value

find key map returns the value associated with key in map if present.

  • raises Not_found

    if key is absent from map

val find_opt : 'key key -> 'map t -> ('key, 'map) value option

Same as find, but returns None for Not_found

val mem : 'key key -> 'map t -> bool

mem key map returns true iff key is bound in map, O(log(n)) complexity.

val remove : 'key key -> 'map t -> 'map t

Returns a map with the element removed, O(log(n)) complexity. Returns a physically equal map if the element is absent.

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 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 order on KEY.to_int. O(log(n)) complexity.

val insert : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value) -> + 'map t -> + 'map t

insert key f map modifies or insert an element of the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val update : + 'a key -> + (('a, 'map) value option -> ('a, 'map) value option) -> + 'map t -> + 'map t

update key f map modifies, insert, or remove an element from the map; f takes None if the value was not previously bound, and Some old where old is the previously bound value otherwise. The function preserves physical equality when possible. It returns None if the element should be removed O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t

Unconditionally adds a value in the map (independently from whether the old value existed). O(log(n)) complexity. Preserves physical equality if the new value is physically equal to the old.

Iterators

val split : 'key key -> 'map t -> 'map t * ('key, 'map) value option * 'map t

split key map splits the map into:

  • submap of map whose keys are smaller than key
  • value associated to key (if present)
  • submap of map whose keys are bigger than key

Where the order is given by the unsigned order on KEY.to_int.

type 'map polyiter = {
  1. f : 'a. 'a key -> ('a, 'map) value -> unit;
}
val iter : 'map polyiter -> 'map t -> unit

iter f m calls f.f on all bindings of m, in the unsigned order on KEY.to_int

type ('acc, 'map) polyfold = {
  1. f : 'a. 'a key -> ('a, 'map) value -> 'acc -> 'acc;
}
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 order on KEY.to_int.

type ('acc, 'map) polyfold2 = {
  1. f : 'a. 'a key -> ('a, 'map) value -> ('a, 'map) value -> 'acc -> 'acc;
}
val fold_on_nonequal_inter : + ('acc, 'map) polyfold2 -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_inter f m1 m2 acc returns 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 order of KEY.to_int.

type ('acc, 'map) polyfold2_union = {
  1. f : 'a. 'a key -> + ('a, 'map) value option -> + ('a, 'map) value option -> + 'acc -> + 'acc;
}
val fold_on_nonequal_union : + ('acc, 'map) polyfold2_union -> + 'map t -> + 'map t -> + 'acc -> + 'acc

fold_on_nonequal_union f m1 m2 acc returns 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 exists in either map (m1 ∪ m2) whose values are physically different. Calls to f.f are performed in the unsigned order of KEY.to_int.

type 'map polypredicate = {
  1. f : 'a. 'a key -> ('a, 'map) value -> bool;
}
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 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. Short-circuiting.

In the following, the *no_share function allows taking arguments of different types (but cannot share subtrees of the map), while the default functions attempt to preserve and benefit from sharing the subtrees (using physical equality to detect sharing).

type ('map1, 'map2) polymap = {
  1. f : 'a. ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polymapi = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value;
}
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 order of KEY.to_int.

type ('map1, 'map2) polyfilter_map = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value option;
}
val filter_map : ('map, 'map) polyfilter_map -> 'map t -> 'map t
val filter_map_no_share : ('map1, 'map2) polyfilter_map -> 'map1 t -> 'map2 t

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 order of KEY.to_int.

type 'map polypretty = {
  1. f : 'a. Stdlib.Format.formatter -> 'a key -> ('a, 'map) value -> unit;
}
val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + 'map polypretty -> + Stdlib.Format.formatter -> + 'map t -> + unit

Pretty-prints a map using the given formatter. pp_sep is called once between each binding, it defaults to Format.pp_print_cut. Bindings are printed in the unsigned order of KEY.to_int

Functions on pairs of maps

type ('map1, 'map2) polysame_domain_for_all2 = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> bool;
}
val reflexive_same_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_same_domain_for_all2 f m1 m2 is true if and only if

  • m1 and m2 have the same domain (set of keys)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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

# let equal m1 m2 = MyMap.reflexive_same_domain_for_all2
+  { f = fun _ v1 v2 -> MyValue.equal v1 v2}
+  m1 m2;;
+val equal : 'a MyMap.t -> 'a MyMap.t -> bool = <fun>
val nonreflexive_same_domain_for_all2 : + ('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 order of KEY.to_int. Exits early if the domains mismatch or if f.f returns false.

val reflexive_subset_domain_for_all2 : + ('map, 'map) polysame_domain_for_all2 -> + 'map t -> + 'map t -> + bool

reflexive_subset_domain_for_all2 f m1 m2 is true if and only if

  • m1's domain is a subset of m2's. (all keys defined in m1 are also defined in m2)
  • for all bindings (k, v1) in m1 and (k, v2) in m2, f.f k v1 v2 holds

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 order of KEY.to_int. Exits early if the domains mismatch.

type ('map1, 'map2, 'map3) polyunion = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_union : ('a, 'a, 'a) polyunion -> 'a t -> 'a t -> 'a t

idempotent_union f map1 map2 returns a map whose keys is the union of the keys of map1 and map2. f.f is used to combine the values of keys mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

type ('map1, 'map2, 'map3) polyinter = {
  1. f : 'a. 'a key -> ('a, 'map1) value -> ('a, 'map2) value -> ('a, 'map3) value;
}
val idempotent_inter : ('a, 'a, 'a) polyinter -> 'a t -> 'a t -> 'a t

idempotent_inter f map1 map2 returns a map whose keys is the intersection of the keys of map1 and map2. f.f is used to combine the values a key is mapped in both maps.

Assumes f.f idempotent (i.e. f key value value == value) f.f is called in the 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 different keys between map1 and map2.

val nonidempotent_inter_no_share : + ('a, 'b, 'c) polyinter -> + 'a t -> + 'b t -> + 'c t

nonidempotent_inter_no_share f map1 map2 is the same as idempotent_inter but doesn't preverse physical equality, doesn't assume f.f is idempotent, and can change the type of values. f.f is called on every shared binding. f.f is called in increasing unsigned order of keys. O(n) complexity

type ('map1, 'map2, 'map3) polyinterfilter = {
  1. f : 'a. 'a key -> + ('a, 'map1) value -> + ('a, 'map2) value -> + ('a, 'map3) value option;
}
val idempotent_inter_filter : + ('a, 'a, 'a) polyinterfilter -> + 'a t -> + 'a t -> + 'a t

idempotent_inter_filter f map1 map2 is the same as idempotent_inter but f.f can return None to remove a binding from the resutling map.

type ('map1, 'map2, 'map3) polymerge = {
  1. f : 'a. 'a key -> + ('a, 'map1) value option -> + ('a, 'map2) value option -> + ('a, 'map3) value option;
}
val slow_merge : + ('map1, 'map2, 'map3) polymerge -> + 'map1 t -> + 'map2 t -> + 'map3 t

This is the same as Stdlib.Map.S.merge

val disjoint : 'a t -> 'a t -> bool

disjoint m1 m2 is true iff m1 and m2 have disjoint domains

Conversion functions

val to_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_seq m iterates the whole map, in increasing unsigned order of KEY.to_int

val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t

to_rev_seq m iterates the whole map, in decreasing unsigned order of KEY.to_int

val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t

add_seq s m adds all bindings of the sequence s to m in order.

val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t

of_seq s creates a new map from the bindings of s. If a key is bound multiple times in s, the latest binding is kept

val of_list : 'a key_value_pair list -> 'a t

of_list l creates a new map from the bindings of l. 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 order of KEY.to_int

module WithForeign (Map2 : BASE_MAP with type 'a key = 'a key) : sig ... end

Operation with maps/set of different types. Map2 must use the same KEY.to_int function.

diff --git a/v0.10.0/PatriciaTree/module-type-SET/index.html b/v0.10.0/PatriciaTree/module-type-SET/index.html new file mode 100644 index 0000000..a92cf7f --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-SET/index.html @@ -0,0 +1,10 @@ + +SET (patricia-tree.PatriciaTree.SET)

Module type PatriciaTree.SET

Signature for sets implemented using Patricia trees. Most of this interface should be shared with Stdlib.Set.S.

type elt

The type of elements of the set

type key = elt

Alias for the type of elements, for cross-compatibility with maps

module BaseMap : + HETEROGENEOUS_MAP with type _ key = elt and type (_, _) value = unit

Underlying basemap, for cross map/set operations

type t = unit BaseMap.t

The set type

Basic functions

val empty : t

The empty set

val is_empty : t -> bool

is_empty st is true if st contains no elements, false otherwise

val mem : elt -> t -> bool

mem elt set is true if elt is contained in set, O(log(n)) complexity.

val add : elt -> t -> t

add elt set adds element elt to the set. Preserves physical equality if elt was already present. O(log(n)) complexity.

val singleton : elt -> t

singleton elt returns a set containing a single element: elt

val cardinal : t -> int

cardinal set is the size of the set (number of elements), O(n) complexity.

val is_singleton : t -> elt option

is_singleton set is Some (Any elt) if set is singleton elt and None otherwise.

val remove : elt -> t -> t

remove elt set returns a set containing all elements of set except elt. 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 order on KEY.to_int) if non empty.

  • raises Not_found
val unsigned_max_elt : t -> elt

The maximal element (according to the 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 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 order on KEY.to_int.

Iterators

val iter : (elt -> unit) -> t -> unit

iter f set calls f on all elements of set, in the 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 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 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 order of 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 order on KEY.to_int.

val pretty : + ?pp_sep:(Stdlib.Format.formatter -> unit -> unit) -> + (Stdlib.Format.formatter -> elt -> unit) -> + Stdlib.Format.formatter -> + t -> + unit

Pretty prints the set, pp_sep is called once between each element, it defaults to Format.pp_print_cut

Functions on pairs of sets

val union : t -> t -> t

union a b is the set union of a and b, i.e. the set containing all elements that are either in a or b.

val inter : t -> t -> t

inter a b is the set intersection of a and b, i.e. the set containing all elements that are in both a or b.

val disjoint : t -> t -> bool

disjoint a b is true if a and b have no elements in common.

val equal : t -> t -> bool

equal a b is true if a and b contain the same elements.

val subset : t -> t -> bool

subset a b is true if all elements of a are also in b.

Conversion functions

val to_seq : t -> elt Stdlib.Seq.t

to_seq st iterates the whole set, in increasing unsigned order of KEY.to_int

val to_rev_seq : t -> elt Stdlib.Seq.t

to_rev_seq st iterates the whole set, in decreasing unsigned order of KEY.to_int

val add_seq : elt Stdlib.Seq.t -> t -> t

add_seq s st adds all elements of the sequence s to st in order.

val of_seq : elt Stdlib.Seq.t -> t

of_seq s creates a new set from the elements of s.

val of_list : elt list -> t

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 order of KEY.to_int

diff --git a/v0.10.0/PatriciaTree/module-type-VALUE/index.html b/v0.10.0/PatriciaTree/module-type-VALUE/index.html new file mode 100644 index 0000000..ef11911 --- /dev/null +++ b/v0.10.0/PatriciaTree/module-type-VALUE/index.html @@ -0,0 +1,4 @@ + +VALUE (patricia-tree.PatriciaTree.VALUE)

Module type PatriciaTree.VALUE

Module type used for specifying custom homogeneous value types in MakeCustomMap. For most purposes, use the provided Value implementation. It sets 'a t = 'a, which is the desired effect (maps can map to any value). This is the case in MakeMap. However, for maps like Hash-consed maps and sets, it can be useful to restrict the type of values in order to implement hash and polyeq functions on values. See the HASHED_VALUE module type for more details.

type 'a t

The type of values. A 'map map maps key to 'map value. Can be mutable if desired, unless it is being used in Hash-consed maps and sets.

diff --git a/v0.10.0/db.js b/v0.10.0/db.js new file mode 100644 index 0000000..60a4490 --- /dev/null +++ b/v0.10.0/db.js @@ -0,0 +1 @@ +function sherlodoc_db () { return "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"; } diff --git a/v0.10.0/index.html b/v0.10.0/index.html new file mode 100644 index 0000000..df03313 --- /dev/null +++ b/v0.10.0/index.html @@ -0,0 +1,97 @@ + +index (patricia-tree.index)

Package patricia-tree

This library contains a single module: PatriciaTree.

This is version 0.10.0 of the library. It is known to work with OCaml versions ranging from 4.14 to 5.2.

This is an OCaml library that implements sets and maps as Patricia Trees, as described in Okasaki and Gill's 1998 paper Fast mergeable integer maps. It is a space-efficient prefix trie over the big-endian representation of the key's integer identifier.

The source code of this library is available on Github under an LGPL-2.1 license.

This library was written by Matthieu Lemerre, then further improved by Dorian Lesbre, as part of the Codex semantics library, developed at CEA List.

Installation

This library can be installed with opam:

opam install patricia-tree

Alternatively, you can clone the source repository and install with dune:

git clone git@github.com:codex-semantics-library/patricia-tree.git
+cd patricia-tree
+opan install . --deps-only
+dune build -p patricia-tree
+dune install
+# To build documentation
+opam install . --deps-only --with-doc
+dune build @doc

Features

Quick overview

Functors

This library contains a single module, PatriciaTree. The functors used to build maps and sets are the following:

Interfaces

Here is a brief overview of the various module types of our library:

Examples

Homogeneous map

Here is a small example of a non-generic map:

  1. Start by creating a key module:

    module IntKey : PatriciaTree.KEY with type t = int = struct
    +  type t = int
    +  let to_int x = x
    +end
  2. Use it to instanciate the map/set functors:

    module IMap : PatriciaTree.MAP with type key = int = PatriciaTree.MakeMap(IntKey);;
    +module ISet : PatriciaTree.SET with type elt = int = PatriciaTree.MakeSet(IntKey);;
  3. You can now use it as you would any other map:

    # let map =
    +  IMap.empty |>
    +  IMap.add 1 "hello" |>
    +  IMap.add 2 "world" |>
    +  IMap.add 3 "how do you do?";;
    +val map : string IMap.t = <abstr>

    (We also have of_list and of_seq functions for quick initialization)

    # IMap.find 1 map;;
    +- : string = "hello"
    +# IMap.cardinal map;;
    +- : int = 3
  4. The strength of Patricia Tree is the speedup of operation on multiple maps with common subtrees.

    # let map2 =
    +    IMap.idempotent_inter_filter (fun _key _l _r -> None)
    +      (IMap.add 4 "something" map)
    +      (IMap.add 5 "something else" map);;
    +val map2 : string IMap.t = <abstr>
    +# map == map2;;
    +- : bool = true

    Physical equality is preserved as much as possible, although some intersections may need to build new nodes and won't be fully physically equal, they will still share subtrees if possible.

    # let str = IMap.find 1 map;;
    +val str : string = "hello"
    +# IMap.add 1 str map == map (* already present *);;
    +- : bool = true
    +# IMap.add 1 "hello" map == map
    +  (* new string copy isn't physically equal to the old one *);;
    +- : bool = false

    Note that physical equality ins't preserved when creating new copies of values (the newly created string "hello" isn't physically equal to str). It can also fail when maps have the same bindings but were created differently:

    # let map3 = IMap.remove 2 map;;
    +val map3 : string IMap.t = <abstr>
    +# IMap.add 2 (IMap.find 2 map) map3 == map;;
    +- : bool = false

    This is because they were created through different processes. They will still share subtrees. If you want to maintain full physical equality (and thus get cheap equality test between maps), use the provided hash-consed maps and sets.

  5. Our library also allows cross map/set operations. For example, you can only keep the bindings of map whose keys are in a given set:

    let set = ISet.of_list [1; 3]
    +module CrossOperations = IMap.WithForeign(ISet.BaseMap)
    +let restricted_map = CrossOperations.nonidempotent_inter
    +  { f = fun _key value () -> value } map set
    # IMap.to_list map;;
    +- : (int * string) list = [(1, "hello"); (2, "world"); (3, "how do you do?")]
    +# IMap.to_list restricted_map;;
    +- : (int * string) list = [(1, "hello"); (3, "how do you do?")]

Heterogeneous map

Heterogeneous maps work very similarly to homogeneous ones, but come with extra liberty of having a generic type as a key.

  1. Here is a GADT example to use for our keys: a small typed expression language.

    type 'a expr =
    +  | G_Const_Int : int -> int expr
    +  | G_Const_Bool : bool -> bool expr
    +  | G_Addition : int expr * int expr -> int expr
    +  | G_Equal : 'a expr * 'a expr -> bool expr

    We can create our HETEROGENEOUS_KEY functor parameter using this type has follows:

    module Expr : PatriciaTree.HETEROGENEOUS_KEY with type 'a t = 'a expr = struct
    +  type 'a t = 'a expr
    +
    +  (** Injective, so long as expression are small enough
    +      (encodes the constructor discriminant in two lowest bits).
    +      Ideally, use a hash-consed type, to_int needs to be fast *)
    +  let rec to_int : type a. a expr -> int = function
    +    | G_Const_Int i ->   0 + 4*i
    +    | G_Const_Bool b ->  1 + 4*(if b then 1 else 0)
    +    | G_Addition(l,r) -> 2 + 4*(to_int l mod 10000 + 10000*(to_int r))
    +    | G_Equal(l,r) ->    3 + 4*(to_int l mod 10000 + 10000*(to_int r))
    +
    +  (** Full polymorphic equality *)
    +  let rec polyeq : type a b. a expr -> b expr -> (a, b) PatriciaTree.cmp =
    +    fun l r -> match l, r with
    +    | G_Const_Int l, G_Const_Int r -> if l = r then Eq else Diff
    +    | G_Const_Bool l, G_Const_Bool r -> if l = r then Eq else Diff
    +    | G_Addition(ll, lr), G_Addition(rl, rr) -> (
    +        match polyeq ll rl with
    +        | Eq -> polyeq lr rr
    +        | Diff -> Diff)
    +    | G_Equal(ll, lr), G_Equal(rl, rr) ->    (
    +        match polyeq ll rl with
    +        | Eq -> (match polyeq lr rr with Eq -> Eq | Diff -> Diff) (* Match required by typechecker *)
    +        | Diff -> Diff)
    +    | _ -> Diff
    +end
  2. We can now instanciate our map functor. Note that in the heterogeneous case, we must also specify the value type (second functor argument) and how it depends on the key type (first parameter) and the map type (second parameter). Here the value only depends on the type of the key, not that of the map

    module EMap = PatriciaTree.MakeHeterogeneousMap(Expr)(struct type ('a, _) t = 'a end)
  3. You can now use this as you would any other dependent map:

    # let map : unit EMap.t =
    +  EMap.empty |>
    +  EMap.add (G_Const_Bool false) false |>
    +  EMap.add (G_Const_Int 5) 5 |>
    +  EMap.add (G_Addition (G_Const_Int 3, G_Const_Int 6)) 9 |>
    +  EMap.add (G_Equal (G_Const_Bool false, G_Equal (G_Const_Int 5, G_Const_Int 7))) true
    +val map : unit EMap.t = <abstr>
    +# EMap.find (G_Const_Bool false) map;;
    +- : bool = false
    +# EMap.find (G_Const_Int 5) map;;
    +- : int = 5
    +# EMap.cardinal map;;
    +- : int = 4
  4. Physical equality preservation allows fast operations on multiple maps with common ancestors. In the heterogeneous case, these functions are a bit more complex since OCaml requires that first-order polymorphic functions be wrapped in records:

    # let map2 = EMap.idempotent_inter_filter
    +    { f = fun _key _l _r -> None } (* polymorphic 1rst order functions are wrapped in records *)
    +    (EMap.add (G_Const_Int 0) 8 map)
    +    (EMap.add (G_Const_Int 0) 9 map)
    +val map2 : unit EMap.t = <abstr>

    Even though map and map2 have the same elements, they may not always be physically equal:

    # map == map2;;
    +- : bool = false

    This is because they were created through different processes. They will still share subtrees. If you want to maintain full physical equality (and thus get cheap equality test between maps), use the provided hash-consed maps and sets.

Release status

This should be close to a stable release. It is already being used as part of a larger project successfully, and this usage as helped us mature the interface. As is, we believe the project is usable, and we don't anticipate any major change before 1.0.0. We didn't commit to a stable release straight away as we would like a bit more time using this library before doing so.

Known issues

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 (instead of just using 'b)

type (_, 'b) snd = Snd of 'b [@@unboxed]

It should not incur any extra performance cost as it is unboxed, but can appear when manipulating non-generic maps.

For more details about this issue, see the OCaml discourse discussion.

Comparison to other OCaml libraries

ptmap and ptset

There are other implementations of Patricia Tree in OCaml, namely ptmap and ptset, both by J.C. Filliatre. These are smaller and closer to OCaml's built-in Map and Set, however:

dmap

Additionally, there is a dependent map library: dmap, which gave us the idea of making our PatriciaTree dependent. It allows creating type safe dependent maps similar to our heterogeneous maps. However, its maps aren't Patricia trees. They are binary trees build using a (polymorphic) comparison function, similarly to the maps of the standard library.

Another difference is that the type of values in the map is independent from the type of the keys, allowing keys to be associated with different values in different maps. i.e. we map 'a key to any ('a, 'b) value type, whereas dmap only maps 'a key to 'a or 'a value.

dmap also works with OCaml >= 4.12, whereas we require OCaml >= 4.14.

Contributions and bug reports

Any contributions are welcome!

You can report any bug, issues, or desired features using the Github issue tracker. Please include OCaml, dune, and library version information in you bug reports.

If you want to contribute code, feel free to fork the repository on Github and open a pull request. By doing so you agree to release your code under this project's license (LGPL-2.1).

There is no imposed coding style for this repository, here are just a few guidelines and conventions: