Module type PatriciaTree.HeterogeneousMap_S

This is the same as Map_S, 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_S are:

include BaseMap_S
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
val leaf : 'key key -> ('key, 'map) value -> 'map t
val branch : prefix:intkey -> branching_bit:mask -> tree0:'map t -> tree1:'map t -> 'map t

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

    Branching bit contains only one bit set; the corresponding mask is (branching_bit - 1). The prefixes are normalized: the bits below the branching bit are set to zero (i.e. prefix & (branching_bit - 1) = 0).

    *)
  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
val view : 'a t -> 'a view

Convert the map to a view

type 'map key_value_pair =
  1. | KeyValue : 'a key * ('a, 'map) value -> 'map key_value_pair
val min_binding : 'a t -> 'a key_value_pair
  • raises Not_found

    if the map is empty

val max_binding : 'a t -> 'a key_value_pair
  • raises Not_found

    if the map is empty

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

The size of the map

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
  • 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
val remove : 'key key -> 'map t -> 'map t
val pop_minimum : 'map t -> ('map key_value_pair * 'map t) option
val pop_maximum : 'map t -> ('map key_value_pair * 'map t) option
val insert : 'a key -> (('a, 'map) value option -> ('a, 'map) value) -> 'map t -> 'map t
val update : 'a key -> (('a, 'map) value option -> ('a, 'map) value option) -> 'map t -> 'map t
val add : 'key key -> ('key, 'map) value -> 'map t -> 'map t
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 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 order given by 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 order given by 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 order given by Key.to_int

val for_all : 'map polypredicate -> 'map t -> bool

for_all f m checks that f holds on all bindings of m7 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 order given by 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 order given by 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 order given by 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 order given by Key.to_int

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

It is useful to implement equality on maps:

let equal m1 m2 = reflexive_same_domain_for_all2
  { f = fun _ v1 v2 -> Value.equal v1 v2}
  m1 m2
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 order of Key.to_int. Exits early if the domains mismatch.

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 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 order given by 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 order given by 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 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
val to_rev_seq : 'a t -> 'a key_value_pair Stdlib.Seq.t
val add_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t -> 'a t
val of_seq : 'a key_value_pair Stdlib.Seq.t -> 'a t
val of_list : 'a key_value_pair list -> 'a t
val to_list : 'a t -> 'a key_value_pair list
module WithForeign (Map2 : BaseMap_S with type 'a key = 'a key) : sig ... end