123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202(**
This module provides a means by which a registry of "witnesses" can be
created. Here, a witness is a representative of another (typically more
complex) value. A witness registry is a mutable structure which
monotonically accumulates values, mapping distinct values to distinct
witnesses. The primary use of such a registry is to accelerate comparison
operations. For instance, using witnesses as keys in a tree-based dictionary
may be faster than using the original values if the comparison between two
values is an expensive operation.
*)openBatteries;;(**
This module type describes the information required to create a witness
registry module.
*)moduletypeSpec=sigtypetvalcompare:t->t->intend;;(**
This is the type of a witness registry module.
*)moduletypeRegistry=sig(** The type of a witness registry. *)typet(** The type of elements stored in the registry. *)typeelt(** The type of a witness in the registry. *)typewitness(** A function to produce an empty witness registry. Registries use mutable
data structures to cache results, so each empty registry must be created
separately. *)valempty_registry:unit->t(** Obtains a witness for the provided value. If the value already has a
witness, it is returned; otherwise, a new witness is created and
returned. If the same element is added to two different registries, it
will not be given the same witness for each. *)valwitness_of:t->elt->witness(** Obtains a value for the provided witness. Raises Not_found if no such
witness is stored in the provided registry. *)valelement_of:t->witness->elt(** Determines if two witnesses are equal. Two witnesses are equal only if
they witness the same value. *)valequal_witness:witness->witness->bool(** Compares two witnesses. This comparison operation is arbitrary; although
the element type must be comparable, there is no guarantee of a connection
between the comparison of elements and the comparison of their
witnesses. *)valcompare_witness:witness->witness->intend;;(**
A functor which creates witness registries.
*)moduleMake(S:Spec):Registrywithtypeelt=S.t=structtypeelt=S.t;;typewitness=int;;letequal_witness:int->int->bool=(* This use of "==" (instead of "=") is intentional: OCaml's == is a single
machine instruction and, on primitive integers, identity is equality. *)(==);;letcompare_witness:int->int->int=compare;;moduleWitness_ord=structtypet=witnessletcompare=compare_witnessend;;moduleWitness_map=Map.Make(Witness_ord);;moduleElement_map=Map.Make(S);;letnext_available_witness:witnessref=ref0;;typet={witness_to_value:eltWitness_map.tref;value_to_witness:witnessElement_map.tref};;letempty_registry()={witness_to_value=refWitness_map.empty;value_to_witness=refElement_map.empty;};;letwitness_of(r:t)(x:elt):witness=matchElement_map.Exceptionless.findx!(r.value_to_witness)with|None->letw=!next_available_witnessinnext_available_witness:=w+1;r.value_to_witness:=Element_map.addxw!(r.value_to_witness);r.witness_to_value:=Witness_map.addwx!(r.witness_to_value);w|Somew->w;;letelement_of(r:t)(w:witness):elt=Witness_map.findw!(r.witness_to_value);;end;;(** The type of a registry with an escort. Escorts pair the witnesses with
their registries to make operations such as pretty-printing easier. This
module only defines escorts and their basic comparison operations. More
operations can be added by including utils modules produced by the other
functors in this module. *)moduletypeEscorted_registry=sigincludeRegistry;;typeescorted_witnessvalwitness_of_escorted_witness:escorted_witness->witnessvalregistry_of_escorted_witness:escorted_witness->tvalelement_of_escorted_witness:escorted_witness->eltvalescorted_witness_of:t->elt->escorted_witnessvalshare_escort:escorted_witness->elt->escorted_witnessvalequal_escorted_witness:escorted_witness->escorted_witness->boolvalcompare_escorted_witness:escorted_witness->escorted_witness->intend;;(** A functor to make registries with escorts. *)moduleMake_escorted(S:Spec):Escorted_registrywithtypeelt=S.t=structmoduleEscorted_registry=Make(S);;includeEscorted_registry;;typeescorted_witness=t*witness;;letwitness_of_escorted_witness(_,w)=w;;letregistry_of_escorted_witness(r,_)=r;;letelement_of_escorted_witness(r,w)=element_ofrw;;letescorted_witness_ofre=(r,witness_ofre);;letshare_escort(r,_)e=(r,witness_ofre);;letequal_escorted_witness(_,w1)(_,w2)=equal_witnessw1w2;;letcompare_escorted_witness(_,w1)(_,w2)=compare_witnessw1w2;;end;;(** The type of a pretty-printing utility module for witness registries. *)moduletypePp_utils=sigtypeescorted_witness(** A pretty printer for escorted witnesses (given a pretty printer for their
values. *)valpp_escorted_witness:escorted_witnessPp_utils.pretty_printerend;;(** A functor to produce a pretty-printing utility module. *)moduleMake_pp(R:Escorted_registry)(P:Pp_utils.Ppwithtypet=R.elt):Pp_utilswithtypeescorted_witness:=R.escorted_witness=structletpp_escorted_witnessfmtew=P.ppfmt@@R.element_of(R.registry_of_escorted_witnessew)(R.witness_of_escorted_witnessew);;end;;(** The type of a to-yojson utility module for witness registries. *)moduletypeTo_yojson_utils=sigtypeescorted_witness(** A pretty printer for escorted witnesses (given a pretty printer for their
values. *)valescorted_witness_to_yojson:escorted_witness->Yojson.Safe.tend;;(** A functor to produce a pretty-printing utility module. *)moduleMake_to_yojson(R:Escorted_registry)(Y:Yojson_utils.To_yojson_typewithtypet=R.elt):To_yojson_utilswithtypeescorted_witness:=R.escorted_witness=structletescorted_witness_to_yojsonew=Y.to_yojson@@R.element_of(R.registry_of_escorted_witnessew)(R.witness_of_escorted_witnessew);;end;;