123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233(** Universal/heterogeneous maps, useful for storing values of arbitrary type in a single
map.
In order to recover a value, it must be looked up with exactly the [Key.t] it was
stored in. In other words, given different [Key.t]s from the same [string], one will
not be able to recover the key stored in the other one.
This is similar to [Univ] in spirit.
*)open!BasemoduletypeKey=sigtype'at[@@derivingsexp_of](** For correct behavior of the map, [type_id] must return the same [Type_equal.Id] on
different calls on the same input. *)valtype_id:'at->'aType_equal.Id.tendmoduletypeData=sigtype'at[@@derivingsexp_of]endmoduletypeData1=sigtype('s,'a)t[@@derivingsexp_of]endmoduletypeS1=sig(** The ['s] parameter is shared across all values stored in the map. *)type'st[@@derivingsexp_of]moduleKey:Keytype('s,'a)datavalinvariant:_t->unitvalempty:_tvalsingleton:'aKey.t->('s,'a)data->'stvalis_empty:_t->boolvalset:'st->key:'aKey.t->data:('s,'a)data->'stvalmem:_t->_Key.t->boolvalmem_by_id:_t->Type_equal.Id.Uid.t->boolvalfind:'st->'aKey.t->('s,'a)dataoptionvalfind_exn:'st->'aKey.t->('s,'a)datavaladd:'st->key:'aKey.t->data:('s,'a)data->[`Okof'st|`Duplicate]valadd_exn:'st->key:'aKey.t->data:('s,'a)data->'stvalchange:'st->'aKey.t->f:(('s,'a)dataoption->('s,'a)dataoption)->'stvalchange_exn:'st->'aKey.t->f:(('s,'a)data->('s,'a)data)->'stvalupdate:'st->'aKey.t->f:(('s,'a)dataoption->('s,'a)data)->'stvalremove:'st->'aKey.t->'stvalremove_by_id:'st->Type_equal.Id.Uid.t->'stmodulePacked:sigtype'st=T:'aKey.t*('s,'a)data->'stendvalkey_id_set:'st->Set.M(Type_equal.Id.Uid).tvalto_alist:'st->'sPacked.tlistvalof_alist_exn:'sPacked.tlist->'stvalfind_packed_by_id:'st->Type_equal.Id.Uid.t->'sPacked.toptionvalfind_packed_by_id_exn:'st->Type_equal.Id.Uid.t->'sPacked.tvaltype_equal:('st,'sPacked.tMap.M(Type_equal.Id.Uid).t)Type_equal.tendmoduletypeS=sigtypet[@@derivingsexp_of]moduleKey:Keytype'adataincludeInvariant.Swithtypet:=tvalempty:tvalsingleton:'aKey.t->'adata->tvalis_empty:t->boolvalset:t->key:'aKey.t->data:'adata->tvalmem:t->'aKey.t->boolvalmem_by_id:t->Type_equal.Id.Uid.t->boolvalfind:t->'aKey.t->'adataoptionvalfind_exn:t->'aKey.t->'adatavaladd:t->key:'aKey.t->data:'adata->[`Okoft|`Duplicate]valadd_exn:t->key:'aKey.t->data:'adata->tvalchange:t->'aKey.t->f:('adataoption->'adataoption)->tvalchange_exn:t->'aKey.t->f:('adata->'adata)->tvalupdate:t->'aKey.t->f:('adataoption->'adata)->tvalremove:t->'aKey.t->tvalremove_by_id:t->Type_equal.Id.Uid.t->tmodulePacked:sigtype'st1=T:'aKey.t*'adata->'st1typet=unitt1endvalkey_id_set:t->Set.M(Type_equal.Id.Uid).t(** [to_alist t] returns all values in [t], in increasing order of key type-id name. *)valto_alist:t->Packed.tlistvalof_alist_exn:Packed.tlist->tvalfind_packed_by_id:t->Type_equal.Id.Uid.t->Packed.toptionvalfind_packed_by_id_exn:t->Type_equal.Id.Uid.t->Packed.tvaltype_equal:(t,Packed.tMap.M(Type_equal.Id.Uid).t)Type_equal.tendmoduletypeUniv_map=sigmoduletypeS=SmoduletypeS1=S1moduletypeKey=KeymoduletypeData=DatamoduleType_id_key:Keywithtype'at='aType_equal.Id.tincludeSwithtype'adata='aandmoduleKey:=Type_id_key(** This binding is convenient because existing call sites often refer to
[Univ_map.Key.create].
*)moduleKey=Type_equal.IdmoduleMake(Key:Key)(Data:Data):Swithtype'adata='aData.tandmoduleKey=KeymoduleMake1(Key:Key)(Data:Data1):S1withtype('s,'a)data=('s,'a)Data.tandmoduleKey=KeymoduleMerge(Key:Key)(Input1_data:Data)(Input2_data:Data)(Output_data:Data):sigtypef={f:'a.key:'aKey.t->[`Leftof'aInput1_data.t|`Rightof'aInput2_data.t|`Bothof'aInput1_data.t*'aInput2_data.t]->'aOutput_data.toption}(** The analogue of the normal [Map.merge] function. *)valmerge:Make(Key)(Input1_data).t->Make(Key)(Input2_data).t->f:f->Make(Key)(Output_data).tendmoduleMerge1(Key:Key)(Input1_data:Data1)(Input2_data:Data1)(Output_data:Data1):sigtype('s1,'s2,'s3)f={f:'a.key:'aKey.t->[`Leftof('s1,'a)Input1_data.t|`Rightof('s2,'a)Input2_data.t|`Bothof('s1,'a)Input1_data.t*('s2,'a)Input2_data.t]->('s3,'a)Output_data.toption}(** The analogue of the normal [Map.merge] function. *)valmerge:'s1Make1(Key)(Input1_data).t->'s2Make1(Key)(Input2_data).t->f:('s1,'s2,'s3)f->'s3Make1(Key)(Output_data).tend(** keys with associated default values, so that [find] is no longer partial *)moduleWith_default:sigmoduleKey:sigtype'atvalcreate:default:'a->name:string->('a->Sexp.t)->'atvalid:'at->'aType_equal.Id.tendvalset:t->key:'aKey.t->data:'a->tvalfind:t->'aKey.t->'avalchange:t->'aKey.t->f:('a->'a)->tend(** keys that map to an accumulator value with an associated fold operation *)moduleWith_fold:sigmoduleKey:sigtype('a,'b)tvalcreate:init:'b->f:('b->'a->'b)->name:string->('b->Sexp.t)->('a,'b)tvalid:('a,'b)t->'bType_equal.Id.tend(** reset the accumulator *)valset:t->key:('a,'b)Key.t->data:'b->t(** the current accumulator *)valfind:t->('a,'b)Key.t->'b(** fold value into accumulator *)valadd:t->key:('a,'b)Key.t->data:'a->t(** accumulator update *)valchange:t->('a,'b)Key.t->f:('b->'b)->tend(** list-accumulating keys with a default value of the empty list *)moduleMulti:sigmoduleKey:sigtype'atvalcreate:name:string->('a->Sexp.t)->'atvalid:'at->'alistType_equal.Id.tendvalset:t->key:'aKey.t->data:'alist->tvalfind:t->'aKey.t->'alistvaladd:t->key:'aKey.t->data:'a->tvalchange:t->'aKey.t->f:('alist->'alist)->tendend