123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170open!Core_kernelmoduletypeS=sigmoduleIncr:sigtype'atmoduleCutoff:sigtype'atendendvalof_set:('k,'cmp)Set.tIncr.t->('k,unit,'cmp)Map.tIncr.tvalfilter_mapi:?data_equal:('v1->'v1->bool)->('k,'v1,'cmp)Map.tIncr.t->f:(key:'k->data:'v1->'v2option)->('k,'v2,'cmp)Map.tIncr.tvalmapi:?data_equal:('v1->'v1->bool)->('k,'v1,'cmp)Map.tIncr.t->f:(key:'k->data:'v1->'v2)->('k,'v2,'cmp)Map.tIncr.tvalfilter_mapi':?cutoff:'v1Incr.Cutoff.t->?data_equal:('v1->'v1->bool)->('k,'v1,'cmp)Map.tIncr.t->f:(key:'k->data:'v1Incr.t->'v2optionIncr.t)->('k,'v2,'cmp)Map.tIncr.tvalmapi':?cutoff:'v1Incr.Cutoff.t->?data_equal:('v1->'v1->bool)->('k,'v1,'cmp)Map.tIncr.t->f:(key:'k->data:'v1Incr.t->'v2Incr.t)->('k,'v2,'cmp)Map.tIncr.t(** [unordered_fold i ~init ~add ~remove] constructs a more incremental version of:
{[
let%map m = i in
Map.fold m ~init ~f:add
]}
assuming that [remove] is the inverse of [add], and that the operations for
different keys can be performed in any order. Note that [data_equal] defaults
to [phys_equal], but a more precise equality can be provided instead.
When the data for a key updates, by default [remove] is called on the old data
and then [add] is called on the new data.
[update] provides an alternative single function to call each time a key's data
updates, and can be used to improve efficiency.
*)valunordered_fold:?data_equal:('v->'v->bool)->?update:(key:'k->old_data:'v->new_data:'v->'acc->'acc)->('k,'v,'cmp)Map.tIncr.t->init:'acc->add:(key:'k->data:'v->'acc->'acc)->remove:(key:'k->data:'v->'acc->'acc)->'accIncr.t(** Like [merge] in [Base.Map.merge]. Note that [f] is called at most once per key in
any given stabilization. *)valmerge:?data_equal_left:('v1->'v1->bool)->?data_equal_right:('v2->'v2->bool)->('k,'v1,'cmp)Map.tIncr.t->('k,'v2,'cmp)Map.tIncr.t->f:(key:'k->[`Leftof'v1|`Rightof'v2|`Bothof'v1*'v2]->'v3option)->('k,'v3,'cmp)Map.tIncr.t(** This is the "easy" version of [join] *)valflatten:('k,'vIncr.t,'cmp)Map.t->('k,'v,'cmp)Map.tIncr.t(** The non-incremental semantics of this function is the identity function. Its
purpose is to collapse the extra level of incrementality at the level of the data of
the map.*)valjoin:('k,'vIncr.t,'cmp)Map.tIncr.t->('k,'v,'cmp)Map.tIncr.tvalseparate:('k,'v,'cmp)Map.tIncr.t->data_equal:('v->'v->sexp_bool)->('k,'vIncr.t,'cmp)Map.tIncr.t(** [subrange map (min, max)] constructs an incremental submap that includes all of the
keys and data from [map] between [min] and [max], inclusive, and none of the keys
outside the range.
[subrange map None] is the empty map. [range] being [None] means no elements are
chosen.
Note that incremental changes have a runtime of O((k + m) log n) where k is the size
of the changes to the underlying map and m is the size of the changes to the
elements contained by the range. The complexity of the initial computation is the
same as the incremental computation, with some simplification. k = 0 because we have
not made any changes to the underlying map yet, and m equals the size of the range,
because the initial range is empty. *)valsubrange:?data_equal:('v->'v->bool)->('k,'v,'cmp)Map.tIncr.t->('k*'k)optionIncr.t->('k,'v,'cmp)Map.tIncr.t(** [('k, 'v) Lookup.t] provides a way to lookup keys in a map which uses symmetric
diffs to trigger updates of the lookups.
The complexity of an update depends on:
- [n]: the number of keys in the larger of the old/updated input map
- [k]: the number of lookup nodes created using [find]
- [m]: the number of elements in the symdiff of the maps
- [symdiff(n)]: the cost of performing the symdiff on the map (m <= symdiff(n) <= n)
Each update should cost [O(symdiff(n) + m * log k)], so this will be efficient when
there are a lot of lookups (close to n) into a map which can be efficiently
symdiffed (and therefore has a small number of changes also). The cost of updating
when performing the same lookups by means of [Incr.map ~f:(fun m -> Map.find m key)]
is [O(k * log n)].
*)moduleLookup:sigtype('k,'v,'cmp)t(** Create the lookup structure on an incremental map. *)valcreate:?data_equal:('v->'v->bool)->('k,'v,'cmp)Map.tIncr.t->comparator:('k,'cmp)Comparator.t->('k,'v,'cmp)t(** Create a node which performs [Map.find] on the input map.
[find (create incr_map) key] should be equivalent to [Incr.map ~f:(fun m ->
Map.find m key) incr_map], but when you call [find] many times for a single
[create] the nodes should update more efficiently in stabilisation when [incr_map]
changes in a way which can be efficiently diffed.
This will re-use existing nodes when it can, but will not always do so.
*)valfind:('k,'v,_)t->'k->'voptionIncr.t(** A convenient way to refer to the type for a given key. *)moduleM(K:sigtypettypecomparator_witnessend):sigtypenonrec'vt=(K.t,'v,K.comparator_witness)tendmoduleFor_debug:sigvalsexp_of_t:('k->Sexp.t)->('v->Sexp.t)->('k,'v,'cmp)t->Sexp.tendendendmoduletypeIncr_map=sig(** Functions for using maps efficiently within Incremental. The goal of the algorithms
here is to do work on the output of the computation proportional to the amount of
work done on the input. i.e., [k] modifications to the input map for some
computation will result in [k] modifications to the output map. The changes to the
input map are typically computed using [Map.symmetric_diff].
Unless stated otherwise, the non-incremental semantics of these functions (i.e..,
ignoring performance) is the same as the corresponding function in Core_kernel's
[Map] module. *)moduleMake(Incr:Incremental.S):SwithmoduleIncr:=Incrend