123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374(**************************************************************************)(* This file is part of the Codex semantics library *)(* (patricia-tree sub-component). *)(* *)(* Copyright (C) 2024-2025 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* You can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file LICENSE). *)(**************************************************************************)openIntsopenSignaturesopenKey_valueopenNodes(** [match_prefix k p m] returns [true] if and only if the key [k] has prefix [p] up to bit [m]. *)letmatch_prefixkpm=maskkm=p(** Returns true if the branch caracterized by the two first arguments
would contain the branch caracterized by the second (as right or left subtree) *)let[@inlinealways]branches_beforel_prefix(l_mask:mask)(r_prefix:intkey)(r_mask:mask)=unsigned_lt(r_mask:>int)(l_mask:>int)&&match_prefix(r_prefix:>int)l_prefixl_maskmoduleMakeCustomHeterogeneousMap(Key:HETEROGENEOUS_KEY)(Value:HETEROGENEOUS_VALUE)(NODE:NODEwithtype'akey='aKey.tandtype('key,'map)value=('key,'map)Value.t):HETEROGENEOUS_MAPwithtype'akey='aKey.tandtype('key,'map)value=('key,'map)Value.tandtype'at='aNODE.t=structmoduleCore=structincludeNODEletrecfindint:typeamap.aKey.t->int->mapt->(a,map)value=funwitnesssearchedm->matchNODE.viewmwith|Leaf{key;value}->beginmatchKey.polyeqkeywitnesswith|Eq->value|Diff->raiseNot_foundend|Branch{branching_bit;tree0;tree1;_}->(* Optional if not (match_prefix searched prefix branching_bit) then raise Not_found
else *)if((branching_bit:>int)landsearched==0)thenfindintwitnesssearchedtree0elsefindintwitnesssearchedtree1|Empty->raiseNot_foundletfindsearchedm=findintsearched(Key.to_intsearched)mletfind_optsearchedm=matchfindsearchedmwith|x->Somex|exceptionNot_found->NoneendincludeCoretype'mapkey_value_pair=KeyValue:'aKey.t*('a,'map)value->'mapkey_value_pair(* Merge trees whose prefix disagree. *)letjoinpatreeapbtreeb=(* Printf.printf "join %d %d\n" pa pb; *)letm=branching_bit(pa:>int)(pb:>int)inletp=mask(pa:>int)(* for instance *)minif((pa:>int)land(m:>int))=0thenbranch~prefix:p~branching_bit:m~tree0:treea~tree1:treebelsebranch~prefix:p~branching_bit:m~tree0:treeb~tree1:treealetsingleton=leafletreccardinalm=matchNODE.viewmwith|Empty->0|Leaf_->1|Branch{tree0;tree1;_}->cardinaltree0+cardinaltree1letis_singleton m=matchNODE.viewmwith|Leaf{key;value}->Some(KeyValue(key,value))|_->Noneletrecsplit:typeamap.akey->int->mapt->mapt*((a,map)value)option*mapt=funsplit_keysplit_key_intm->matchNODE.viewmwith|Leaf{key;value}->beginmatchKey.polyeqkeysplit_keywith|Eq->NODE.empty,Somevalue,NODE.empty|Diff->ifunsigned_lt(Key.to_intkey)split_key_intthenm,None,NODE.emptyelseNODE.empty,None,mend|Branch{prefix;branching_bit;tree0;tree1}->ifnot(match_prefix split_key_intprefixbranching_bit)thenifunsigned_lt(prefix:>int)split_key_intthenm,None,NODE.emptyelseNODE.empty,None,melseif((branching_bit:>int)landsplit_key_int==0)thenletleft,found,right=splitsplit_keysplit_key_inttree0inleft,found,NODE.branch~prefix~branching_bit~tree0:right~tree1elseletleft,found,right=splitsplit_keysplit_key_inttree1inNODE.branch~prefix~branching_bit~tree0~tree1:left,found,right|Empty->NODE.empty,None,NODE.emptyletsplitkm=splitk(Key.to_intk)mletmemsearchedm=matchfindintsearched(Key.to_intsearched)mwith|exceptionNot_found->false|_->trueletinsert:typeamap.aKey.t->((a,map)Value.toption->(a,map)Value.t)->mapt->mapt=funthekeyft->letthekeyint=Key.to_intthekeyin(* Preserve physical equality whenever possible. *)letexceptionUnmodifiedintryletrecloopt=matchNODE.viewtwith|Empty->leafthekey(fNone)|Leaf{key;value=old}->beginmatchKey.polyeqkeythekeywith|Eq->letnewv=f(Someold)inifnewv==oldthenraiseUnmodifiedelseleafkeynewv|Diff->letkeyint=(Key.to_intkey)injointhekeyint(leafthekey(fNone))keyinttend|Branch{prefix;branching_bit;tree0;tree1}->ifmatch_prefixthekeyintprefixbranching_bitthenif((branching_bit:>int)landthekeyint)==0thenbranch~prefix~branching_bit~tree0:(looptree0)~tree1elsebranch~prefix~branching_bit~tree0~tree1:(looptree1)elsejointhekeyint(leafthekey(fNone))(prefix:>int)tinlooptwithUnmodified->t(* XXXX: This is a better update, that can also remove element, depending on how the join between the old and new values goes.
Can be useful (e.g. when join is top), I should export that, maybe replace insert with it. *)(* TODO: Test. *)letupdate:typeamap.aKey.t->((a,map)Value.toption->(a,map)Value.toption)->mapt->mapt=funthekeyft->letthekeyint=Key.to_intthekeyin(* Preserve physical equality whenever possible. *)letexceptionUnmodifiedintryletrecloopt=matchNODE.viewtwith|Empty->beginmatch(fNone)with|None->raiseUnmodified|Somev->leafthekeyvend|Leaf{key;value=old}->beginmatchKey.polyeqkeythekeywith|Eq->letnewv=f(Someold)inbeginmatchnewvwith|None->empty|Somenewvwhennewv==old->raiseUnmodified|Somenewv->leafkeynewvend|Diff->letkeyint=(Key.to_intkey)inbeginmatchfNonewith|None->raiseUnmodified|Somevalue->jointhekeyint(leafthekeyvalue)keyinttendend|Branch{prefix;branching_bit;tree0;tree1}->ifmatch_prefixthekeyintprefixbranching_bitthenif(thekeyintland(branching_bit:>int))==0thenbranch~prefix~branching_bit~tree0:(looptree0)~tree1elsebranch~prefix~branching_bit~tree0~tree1:(looptree1)elsebeginmatchfNonewith|None->raiseUnmodified|Somevalue->jointhekeyint(leafthekeyvalue)(prefix:>int)tendinlooptwithUnmodified->tletrecremoveintto_removem=matchNODE.viewmwith|Leaf{key;_}when(Key.to_intkey)==to_remove->empty|(Empty|Leaf_)->m|Branch{prefix;branching_bit;tree0;tree1}->if((branching_bit:>int)landto_remove)==0thenbeginlettree0'=removeintto_removetree0iniftree0'==emptythentree1elseiftree0'==tree0thenmelsebranch~prefix~branching_bit~tree0:tree0'~tree1endelsebeginlettree1'=removeintto_removetree1iniftree1'==emptythentree0elseiftree1'==tree1thenmelsebranch~prefix~branching_bit~tree0~tree1:tree1'endletaddkeyvaluet=insertkey(fun_->value)tletremoveto_removem=removeint(Key.to_intto_remove)mmoduleWithForeign(Map2:NODE_WITH_FINDwithtype'akey='akey)=struct(* Intersects the first map with the values of the second map,
trying to preserve physical equality of the first map whenever
possible. *)type('map1,'map2)polyinter_foreign={f:'a.'akey->('a,'map1)value->('a,'map2)Map2.value->('a,'map1)value}[@@unboxed]letrecnonidempotent_interftatb=matchNODE.viewta,Map2.viewtbwith|Empty,_|_,Empty->NODE.empty|Leaf{key;value},_->(tryletres=Map2.findkeytbinletnewval=(f.fkeyvalueres)inifnewval==valuethentaelseNODE.leafkeynewvalwithNot_found->NODE.empty)|_,Leaf{key;value}->(tryletres=findkeytainNODE.leafkey(f.fkeyresvalue)withNot_found->NODE.empty)|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: merge the subtrees *)thenlettree0=(nonidempotent_interfta0tb0)inlettree1=(nonidempotent_interfta1tb1)inif(ta0==tree0&&ta1==tree1)thentaelseNODE.branch~prefix:pa~branching_bit:ma~tree0~tree1elseifbranches_beforepamapbmbthenif(ma:>int)land(pb:>int)==0thennonidempotent_interfta0tbelsenonidempotent_interfta1tbelseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thennonidempotent_interftatb0elsenonidempotent_interftatb1elseNODE.emptytype('map2,'map1)polyfilter_map={f:'a.'aKey.t->('a,'map2)Map2.value->('a,'map1)valueoption}[@@unboxed]letrecfilter_map_no_share(f:('b,'c)polyfilter_map)m=matchMap2.viewmwith|Empty->empty|Leaf{key;value}->(match(f.fkeyvalue)withSomev->leafkeyv|None->empty)|Branch{prefix;branching_bit;tree0;tree1}->lettree0=filter_map_no_shareftree0inlettree1=filter_map_no_shareftree1inbranch~prefix~branching_bit~tree0~tree1(** Add all the bindings in tb to ta (after transformation). *)type('map1,'map2)polyupdate_multiple={f:'a.'aKey.t->('a,'map1)valueoption->('a,'map2)Map2.value->('a,'map1)valueoption}[@@unboxed]letrecupdate_multiple_from_foreign(tb:'map2Map2.t)f(ta:'map1t)=letupd_tbtb=filter_map_no_share{f=funkeyvalue->f.fkeyNonevalue}tbinmatchNODE.viewta,Map2.viewtbwith|Empty,_->upd_tbtb|_,Empty->ta|_,Leaf{key;value}->updatekey(funmaybeval->f.fkeymaybevalvalue)ta|Leaf{key;value},_->letfound=reffalseinletf:typea.akey->(a,'map2)Map2.value->(a,'map1)valueoption=funcurkeycurvalue->matchKey.polyeqkeycurkeywith|Eq->found:=true;f.fcurkey(Somevalue)curvalue|Diff->f.fcurkeyNonecurvalueinletres=filter_map_no_share{f}tbinif!foundthenreselseaddkeyvalueres|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: merge the subtrees *)thenlettree0=update_multiple_from_foreigntb0fta0inlettree1=update_multiple_from_foreigntb1fta1iniftree0==ta0&&tree1==ta1thentaelsebranch~prefix:pa~branching_bit:ma~tree0~tree1elseifbranches_beforepamapbmbthenif(ma:>int)land(pb:>int)==0thenletta0'=update_multiple_from_foreigntbfta0inifta0'==ta0thentaelsebranch~prefix:pa~branching_bit:ma~tree0:ta0'~tree1:ta1elseletta1'=update_multiple_from_foreigntbfta1inifta1'==ta1thentaelsebranch~prefix:pa~branching_bit:ma~tree0:ta0~tree1:ta1'elseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thenlettree0=update_multiple_from_foreigntb0ftainlettree1=upd_tbtb1inbranch~prefix:pb~branching_bit:mb~tree0~tree1elselettree0=upd_tbtb0inlettree1=update_multiple_from_foreigntb1ftainbranch~prefix:pb~branching_bit:mb~tree0~tree1elsejoin(pa:>int)ta(pb:>int)(upd_tbtb)(* Map difference: (possibly) remove from ta elements that are in tb, the other are preserved, no element is added. *)type('map1,'map2,'map3)polyupdate_multiple_inter={f:'a.'aKey.t->('a,'map1)value->('a,'map2)Map2.value->('a,'map3)valueoption}[@@unboxed]letrecupdate_multiple_from_inter_with_foreigntbfta=matchNODE.viewta,Map2.viewtbwith|Empty,_->ta|_,Empty->ta|Leaf{key;value},_->beginmatchMap2.findkeytbwith|exceptionNot_found->ta|foundv->beginmatchf.fkeyvaluefoundvwith|None->empty|Somevwhenv==value->ta|Somev->leafkeyvendend|_,Leaf{key;value}->updatekey(funv->matchvwithNone->None|Somev->f.fkeyvvalue)ta|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: merge the subtrees *)thenlettree0=update_multiple_from_inter_with_foreigntb0fta0inlettree1=update_multiple_from_inter_with_foreigntb1fta1iniftree0==ta0&&tree1==ta1thentaelsebranch~prefix:pa~branching_bit:ma~tree0~tree1elseifbranches_beforepamapbmbthenif(ma:>int)land(pb:>int)==0thenletta0'=update_multiple_from_inter_with_foreigntbfta0inifta0'==ta0thentaelsebranch~prefix:pa~branching_bit:ma~tree0:ta0'~tree1:ta1elseletta1'=update_multiple_from_inter_with_foreigntbfta1inifta1'==ta1thentaelsebranch~prefix:pa~branching_bit:ma~tree0:ta0~tree1:ta1'elseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thenupdate_multiple_from_inter_with_foreigntb0ftaelseupdate_multiple_from_inter_with_foreigntb1ftaelsetatype('map1,'map2)polydifference=('map1,'map2,'map1)polyupdate_multiple_interletrecdifferenceftatb=matchNODE.viewta,Map2.viewtbwith|Empty,_|_,Empty->ta|Leaf{key;value=va},_->(tryletvb=Map2.findkeytbinmatchf.fkeyvavbwith|None->empty|Somev->ifv==vathentaelseleafkeyvwithNot_found->ta)|_,Leaf{key;value}->updatekey(functionNone->None|Somev->f.fkeyvvalue)ta|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pbthenlettree0=differencefta0tb0inlettree1=differencefta1tb1inbranch~prefix:pa~branching_bit:ma~tree0~tree1elseifbranches_beforepamapbmbthenif(ma:>int)land(pb:>int)==0thenbranch~prefix:pa~branching_bit:ma~tree0:(differencefta0tb)~tree1:ta1elsebranch~prefix:pa~branching_bit:ma~tree0:ta0~tree1:(differencefta1tb)elseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thendifferenceftatb0elsedifferenceftatb1elsetatype('a,'b)key_value_value=KeyValueValue:'kkey*('k,'a)value*('k,'b)Map2.value->('a,'b)key_value_valueletrecmin_binding_intertatb=matchNODE.viewta,Map2.viewtbwith|Empty,_|_,Empty->None|Leaf{key;value},_->(trySome(KeyValueValue(key,value,Map2.findkeytb))withNot_found->None)|_,Leaf{key;value}->(trySome(KeyValueValue(key,findkeyta,value))withNot_found->None)|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: iterate on subtrees *)thenmatchmin_binding_interta0tb0with|None->min_binding_interta1tb1|some->someelseifbranches_beforepamapbmbthenif(ma:>int)land(pb:>int)==0thenmin_binding_interta0tbelsemin_binding_interta1tbelseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thenmin_binding_intertatb0elsemin_binding_intertatb1elseNoneletrecmax_binding_intertatb=matchNODE.viewta,Map2.viewtbwith|Empty,_|_,Empty->None|Leaf{key;value},_->(trySome(KeyValueValue(key,value,Map2.findkeytb))withNot_found->None)|_,Leaf{key;value}->(trySome(KeyValueValue(key,findkeyta,value))withNot_found->None)|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: iterate on subtrees *)thenmatchmax_binding_interta1tb1with|None->max_binding_interta0tb0|some->someelseifbranches_beforepamapbmbthenif(ma:>int)land(pb:>int)==0thenmax_binding_interta0tbelsemax_binding_interta1tbelseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thenmax_binding_intertatb0elsemax_binding_intertatb1elseNoneendincludeWithForeign(Core)letrecunsigned_min_bindingx=matchNODE.viewxwith|Empty->raiseNot_found|Leaf{key;value}->KeyValue(key,value)|Branch{tree0;_}->unsigned_min_bindingtree0letrecunsigned_max_bindingx=matchNODE.viewxwith|Empty->raiseNot_found|Leaf{key;value}->KeyValue(key,value)|Branch{tree1;_}->unsigned_max_bindingtree1type('map1,'map2)polymapi={f:'a.'aKey.t->('a,'map1)Value.t->('a,'map2)Value.t}[@@unboxed]letrecmapi(f:('map1,'map1)polymapi)m=matchNODE.viewmwith|Empty->empty|Leaf{key;value}->letnewval=(f.fkeyvalue)inifnewval==valuethenmelseleafkeynewval|Branch{prefix;branching_bit;tree0;tree1}->letnewtree0=mapiftree0inletnewtree1=mapiftree1iniftree0==newtree0&&tree1==newtree1thenmelsebranch~prefix~branching_bit~tree0:newtree0~tree1:newtree1(* MAYBE: A map (and map_filter) homogeneous, that try to preserve physical equality. *)letrecmapi_no_share(f:('map1,'map2)polymapi)m=matchNODE.viewmwith|Empty->empty|Leaf{key;value}->leafkey(f.fkeyvalue)|Branch{prefix;branching_bit;tree0;tree1}->lettree0=mapi_no_shareftree0inlettree1=mapi_no_shareftree1inbranch~prefix~branching_bit~tree0~tree1type('map1,'map2)polymap={f:'a.('a,'map1)Value.t->('a,'map2)Value.t}[@@unboxed]letmap(f:('map1,'map1)polymap)m=mapi{f=fun_v->f.fv}mletmap_no_share(f:('map1,'map2)polymap)m=mapi_no_share{f=fun_v->f.fv}mletrecfilter_map(f:('map1,'map1)polyfilter_map)m=matchNODE.viewmwith|Empty->empty|Leaf{key;value}->(matchf.fkeyvaluewith|None->empty|Somenewval->ifnewval==valuethenmelseleafkeynewval)|Branch{prefix;branching_bit;tree0;tree1}->letnewtree0=filter_mapftree0inletnewtree1=filter_mapftree1iniftree0==newtree0&&tree1==newtree1thenmelsebranch~prefix~branching_bit~tree0:newtree0~tree1:newtree1type'mappolypretty={f:'a.Format.formatter->'aKey.t->('a,'map)Value.t->unit}[@@unboxed]letrecpretty?(pp_sep=Format.pp_print_cut)(f:'mappolypretty)fmtm=matchNODE.viewmwith|Empty->()|Leaf{key;value}->(f.ffmtkeyvalue)|Branch{tree0;tree1;_}->prettyf~pp_sepfmttree0;pp_sepfmt();prettyf~pp_sepfmttree1letrecpop_unsigned_minimumm=matchNODE.viewmwith|Empty->None|Leaf{key;value}->Some(KeyValue(key,value),empty)|Branch{prefix;branching_bit;tree0;tree1}->matchpop_unsigned_minimumtree0with|None->pop_unsigned_minimumtree1|Some(res,tree0')->letrestree=ifis_emptytree0'thentree1elsebranch~prefix~branching_bit~tree0:tree0'~tree1inSome(res,restree)letrecpop_unsigned_maximumm=matchNODE.viewmwith|Empty->None|Leaf{key;value}->Some(KeyValue(key,value),empty)|Branch{prefix;branching_bit;tree0;tree1}->matchpop_unsigned_maximumtree1with|None->pop_unsigned_maximumtree0|Some(res,tree1')->letrestree=ifis_emptytree1'thentree0elsebranch~prefix~branching_bit~tree0~tree1:tree1'inSome(res,restree)(* Note: Insert is a bit weird, I am not sure it should be exported. *)type'mappolyinsert={f:'a.key:'aKey.t->old:('a,'map)Value.t->value:('a,'map)Value.t->('a,'map)Value.t}[@@unboxed]letinsert_for_union:typeamap.mappolyinsert->aKey.t->(a,map)Value.t->mapt->mapt=funfthekeyvaluet->letthekeyint=Key.to_intthekeyin(* Preserve physical equality whenever possible. *)letexceptionUnmodifiedintryletrecloopt=matchNODE.viewtwith|Empty->leafthekeyvalue|Leaf{key;value=old}->beginmatchKey.polyeqkeythekeywith|Eq->ifvalue==oldthenraiseUnmodifiedelseletnewv=f.f~key~old~valueinifnewv==oldthenraiseUnmodifiedelseleafkeynewv|Diff->letkeyint=(Key.to_intkey)injointhekeyint(leafthekeyvalue)keyinttend|Branch{prefix;branching_bit;tree0;tree1}->ifmatch_prefixthekeyintprefixbranching_bitthenif(thekeyintland(branching_bit:>int))==0thenbranch~prefix~branching_bit~tree0:(looptree0)~tree1elsebranch~prefix~branching_bit~tree0~tree1:(looptree1)elsejointhekeyint(leafthekeyvalue)(prefix:>int)tinlooptwithUnmodified->ttype('map1,'map2)polysame_domain_for_all2={f:'a'b.'aKey.t->('a,'map1)Value.t->('a,'map2)Value.t->bool}[@@unboxed](* Fast equality test between two maps. *)letrecreflexive_same_domain_for_all2ftatb=match(NODE.viewta),(NODE.viewtb)with|_whenta==tb->true(* Skip same subtrees thanks to reflexivity. *)|Empty,_|_,Empty->false|Leaf_,Branch_|Branch_,Leaf_->false|Leaf{key=keya;value=valuea},Leaf{key=keyb;value=valueb}->beginmatchKey.polyeqkeyakeybwith|Diff->false|Eq->f.fkeyavalueavaluebend|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->pa==pb&&ma==mb&&reflexive_same_domain_for_all2fta0tb0&&reflexive_same_domain_for_all2fta1tb1letrecnonreflexive_same_domain_for_all2ftatb=match(NODE.viewta),(NODE.viewtb)with|Empty,_|_,Empty->false|Leaf_,Branch_|Branch_,Leaf_->false|Leaf{key=keya;value=valuea},Leaf{key=keyb;value=valueb}->beginmatchKey.polyeqkeyakeybwith|Diff->false|Eq->f.fkeyavalueavaluebend|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->pa==pb&&ma==mb&&nonreflexive_same_domain_for_all2fta0tb0&&nonreflexive_same_domain_for_all2fta1tb1letrecreflexive_subset_domain_for_all2ftatb=match(NODE.viewta),(NODE.viewtb)with|_whenta==tb->true(* Skip same subtrees thanks to reflexivity. *)|Empty,_->true|_,Empty->false|Branch_,Leaf_->false|Leaf{key=keya;value=valuea},viewb->(* Reimplement find locally, mostly because of typing issues
(which could be solved if we had a version of find that
returns a (key,value) pair. *)letsearched=Key.to_intkeyainletrecsearch=function|Leaf{key=keyb;value=valueb}->beginmatchKey.polyeqkeyakeybwith|Diff->false|Eq->f.fkeyavalueavaluebend|Branch{branching_bit;tree0;tree1;_}->if((branching_bit:>int)landsearched==0)thensearch(NODE.viewtree0)elsesearch(NODE.viewtree1)|Empty->false(* Can only happen on weak nodes. *)insearchviewb|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: divide the search. *)then(reflexive_subset_domain_for_all2fta0tb0)&&(reflexive_subset_domain_for_all2fta1tb1)(* Case where ta have to be included in one of tb0 or tb1. *)elseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thenreflexive_subset_domain_for_all2ftatb0elsereflexive_subset_domain_for_all2ftatb1(* Any other case: there are elements in ta that are unmatched in tb. *)elsefalsetype'mappolycompare={f:'a.'akey->('a,'map)value->('a,'map)value->int;}[@@unboxed]letcompare_aux:typeabm.mpolycompare->akey->(a,m)value->bkey->(b,m)value->int->int=funfkavakbvbdefault->letcmp=Int.compare(Key.to_intka)(Key.to_intkb)inifcmp<>0thencmpelsematchKey.polyeqkakbwith|Eq->letcmp=f.fkavavbinifcmp<>0thencmpelsedefault|Diff->default(* Should not happen since same Key.to_int values should imply equality *)letrecreflexive_compareftatb=match(NODE.viewta),(NODE.viewtb)with|_whenta==tb->0|Empty,_->1|_,Empty->-1|Branch_,Leaf{key;value}->letKeyValue(k,v)=unsigned_min_bindingtaincompare_auxfkvkeyvalue1|Leaf{key;value},Branch_->letKeyValue(k,v)=unsigned_min_bindingtbincompare_auxfkeyvaluekv(-1)|Leaf{key;value},Leaf{key=keyb;value=valueb}->compare_auxfkeyvaluekeybvalueb0|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: divide the search. *)thenletcmp=reflexive_comparefta0tb0inifcmp<>0thencmpelsereflexive_comparefta1tb1elseifbranches_beforepbmbpama(* ta has to be included in tb0 or tb1. *)thenif(mb:>int)land(pa:>int)==0thenletcmp=reflexive_compareftatb0inifcmp<>0thencmpelse-1else-1(* ta included in tb1, so there are elements of tb that appear before any elements of ta *)elseifbranches_beforepamapbmb(* tb has to be included in ta0 or ta1. *)thenif(mb:>int)land(pa:>int)==0thenletcmp=reflexive_comparefta0tbinifcmp<>0thencmpelse1else1(* tb included in ta1, so there are elements of ta that appear before any elements of tb *)elseInt.compare(pa:>int)(pb:>int)letrecdisjointtatb=ifta==tbthenis_emptytaelsematchNODE.viewta,NODE.viewtbwith|Empty,_|_,Empty->true|Leaf{key;_},_->not(memkeytb)|_,Leaf{key;_}->not(memkeyta)|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: check both subtrees *)thendisjointta0tb0&&disjointta1tb1elseifbranches_beforepamapbmb(* tb included in ta0 or ta1 *)thenif(ma:>int)land(pb:>int)==0thendisjointta0tbelsedisjointta1tbelseifbranches_beforepbmbpama(* ta included in tb0 or tb1 *)thenif(mb:>int)land(pa:>int)==0thendisjointtatb0elsedisjointtatb1elsetrue(* Different prefixes => no intersection *)type('map1,'map2,'map3)polyunion={f:'a.'aKey.t->('a,'map1)Value.t->('a,'map2)Value.t->('a,'map3)Value.t}[@@unboxed]letrecidempotent_unionftatb=ifta==tbthentaelsematchNODE.viewta,NODE.viewtbwith|Empty,_->tb|_,Empty->ta|Leaf{key;value},_->insert_for_union({f=fun~key~old~value->f.fkeyvalueold})keyvaluetb|_,Leaf{key;value}->insert_for_union({f=fun~key~old~value->f.fkeyoldvalue})keyvalueta|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: merge the subtrees *)then(* MAYBE: if ta0 == tb0 and ta1 == tb1, we can return ta (or
tb). Probably not useful. *)lettree0=idempotent_unionfta0tb0inlettree1=idempotent_unionfta1tb1inbranch~prefix:pa~branching_bit:ma~tree0~tree1elseifbranches_beforepamapbmbthenif(ma:>int)land(pb:>int)==0thenbranch~prefix:pa~branching_bit:ma~tree0:(idempotent_unionfta0tb)~tree1:ta1elsebranch~prefix:pa~branching_bit:ma~tree0:ta0~tree1:(idempotent_unionfta1tb)elseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thenbranch~prefix:pb~branching_bit:mb~tree0:(idempotent_unionftatb0)~tree1:tb1elsebranch~prefix:pb~branching_bit:mb~tree0:tb0~tree1:(idempotent_unionftatb1)elsejoin(pa:>int)ta(pb:>int)tbtype('map1,'map2,'map3)polyinter={f:'a.'aKey.t->('a,'map1)Value.t->('a,'map2)Value.t->('a,'map3)Value.t}[@@unboxed]letrecidempotent_interftatb=ifta==tbthentaelsematchNODE.viewta,NODE.viewtbwith|Empty,_|_,Empty->empty|Leaf{key;value},_->(tryletres=findkeytbinifres==valuethentaelseletnewval=f.fkeyvalueresinifnewval==valuethentaelseleafkeynewvalwithNot_found->empty)|_,Leaf{key;value}->(tryletres=findkeytainifres==valuethentbelseletnewval=f.fkeyresvalueinifnewval==valuethentbelseleafkeynewvalwithNot_found->empty)|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: merge the subtrees *)thenlettree0=idempotent_interfta0tb0inlettree1=idempotent_interfta1tb1inbranch~prefix:pa~branching_bit:ma~tree0~tree1elseifbranches_beforepamapbmbthenif(ma:>int)land(pb:>int)==0thenidempotent_interfta0tbelseidempotent_interfta1tbelseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thenidempotent_interftatb0elseidempotent_interftatb1elseempty(* Same as above, without the same subtree optimisation. *)letrecnonidempotent_inter_no_shareftatb=matchNODE.viewta,NODE.viewtbwith|Empty,_|_,Empty->empty|Leaf{key;value},_->(tryletres=findkeytbinleafkey(f.fkeyvalueres)withNot_found->empty)|_,Leaf{key;value}->(tryletres=findkeytainleafkey(f.fkeyresvalue)withNot_found->empty)|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: merge the subtrees *)thenlettree0=nonidempotent_inter_no_sharefta0tb0inlettree1=nonidempotent_inter_no_sharefta1tb1inbranch~prefix:pa~branching_bit:ma~tree0~tree1elseifbranches_beforepamapbmbthenif(ma:>int)land(pb:>int)==0thennonidempotent_inter_no_sharefta0tbelsenonidempotent_inter_no_sharefta1tbelseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thennonidempotent_inter_no_shareftatb0elsenonidempotent_inter_no_shareftatb1elseemptytype('map1,'map2,'map3)polyinterfilter=('map1,'map2,'map3)polyupdate_multiple_inter={f:'a.'aKey.t->('a,'map1)Value.t->('a,'map2)Value.t->('a,'map3)Value.toption}[@@unboxed]letrecidempotent_inter_filterftatb=ifta==tbthentaelsematchNODE.viewta,NODE.viewtbwith|Empty,_|_,Empty->empty|Leaf{key;value},_->(tryletres=findkeytbinifres==valuethentaelsematch(f.fkeyvalueres)with|Somevwhenv==value->ta|Somev->leafkeyv|None->emptywithNot_found->empty)|_,Leaf{key;value}->(tryletres=findkeytainifres==valuethentbelsematchf.fkeyresvaluewith|Somevwhenv==value->tb|Somev->leafkeyv|None->emptywithNot_found->empty)|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: merge the subtrees *)thenlettree0=idempotent_inter_filterfta0tb0inlettree1=idempotent_inter_filterfta1tb1inbranch~prefix:pa~branching_bit:ma~tree0~tree1elseifbranches_beforepamapbmbthenif(ma:>int)land(pb:>int)==0thenidempotent_inter_filterfta0tbelseidempotent_inter_filterfta1tbelseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thenidempotent_inter_filterftatb0elseidempotent_inter_filterftatb1elseemptytype('map1,'map2,'map3)polymerge={f:'a.'aKey.t->('a,'map1)Value.toption->('a,'map2)Value.toption->('a,'map3)Value.toption}[@@unboxed]letrecslow_merge:typemapamapbmapc.(mapa,mapb,mapc)polymerge->mapaNODE.t->mapbNODE.t->mapcNODE.t=funftatb->letupd_tata=filter_map_no_share{f=funkeyvalue->f.fkey(Somevalue)None}tainletupd_tbtb=filter_map_no_share{f=funkeyvalue->f.fkeyNone(Somevalue)}tbinletoldf=finmatchNODE.viewta,NODE.viewtbwith|Empty,_->upd_tbtb|_,Empty->upd_tata|Leaf{key;value},_->letfound=reffalseinletf:typea.aKey.t->(a,mapb)Value.t->(a,mapc)Value.toption=funcurkeycurvalue->matchKey.polyeqcurkeykeywith|Eq->found:=true;f.fkey(Somevalue)(Somecurvalue)|Diff->f.fcurkeyNone(Somecurvalue)inletres=filter_map_no_share{f}tbin(* If the key of the leaf is not present, add it back. Note
that it breaks the assumption that merge is done in ascending
number of keys; if we wanted that, we would need a
"filter_map_no_share_add_key" function. *)if!foundthenreselsebeginmatcholdf.fkey(Somevalue)Nonewith|None->res|Somevalue->addkeyvalueresend|_,Leaf{key;value}->letfound=reffalseinletf:typea.aKey.t->(a,mapa)Value.t->(a,mapc)Value.toption=funcurkeycurvalue->matchKey.polyeqcurkeykeywith|Eq->found:=true;f.fkey(Somecurvalue)(Somevalue)|Diff->f.fcurkey(Somecurvalue)Noneinletres=filter_map_no_share{f}tainif!foundthenreselsebeginmatcholdf.fkeyNone(Somevalue)with|None->res|Somevalue->addkeyvalueresend|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: merge the subtrees *)thenbranch~prefix:pa~branching_bit:ma~tree0:(slow_mergefta0tb0)~tree1:(slow_mergefta1tb1)elseifbranches_beforepamapbmbthenif(ma:>int)land(pb:>int)==0thenbranch~prefix:pa~branching_bit:ma~tree0:(slow_mergefta0tb)~tree1:(upd_tata1)elsebranch~prefix:pa~branching_bit:ma~tree0:(upd_tata0)~tree1:(slow_mergefta1tb)elseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thenbranch~prefix:pb~branching_bit:mb~tree0:(slow_mergeftatb0)~tree1:(upd_tbtb1)elsebranch~prefix:pb~branching_bit:mb~tree0:(upd_tbtb0)~tree1:(slow_mergeftatb1)elsejoin(pa:>int)(upd_tata)(pb:>int)(upd_tbtb)letrecsymmetric_difference(f:(_,_)polydifference)tatb=ifta==tbthenemptyelsematchNODE.viewta,NODE.viewtbwith|Empty,_->tb|_,Empty->ta|Leaf{key;value},_->(tryletres=findkeytbinifres==valuethenremovekeytbelsematch(f.fkeyvalueres)with|Somevwhenv==res->tb|Somev->addkeyvtb|None->removekeytbwithNot_found->addkeyvaluetb)|_,Leaf{key;value}->(tryletres=findkeytainifres==valuethenremovekeytaelsematchf.fkeyresvaluewith|Somevwhenv==res->ta|Somev->addkeyvta|None->removekeytawithNot_found->addkeyvalueta)|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: merge the subtrees *)thenlettree0=symmetric_differencefta0tb0inlettree1=symmetric_differencefta1tb1inbranch~prefix:pa~branching_bit:ma~tree0~tree1elseifbranches_beforepamapbmbthenif(ma:>int)land(pb:>int)==0thenbranch~prefix:pa~branching_bit:ma~tree0:(symmetric_differencefta0tb)~tree1:ta1elsebranch~prefix:pa~branching_bit:ma~tree0:ta0~tree1:(symmetric_differencefta1tb)elseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thenbranch~prefix:pb~branching_bit:mb~tree0:(symmetric_differenceftatb0)~tree1:tb1elsebranch~prefix:pb~branching_bit:mb~tree0:tb0~tree1:(symmetric_differenceftatb1)elsejoin(pa:>int)ta(pb:>int)tbtype'mappolyiter={f:'a.'aKey.t->('a,'map)Value.t->unit}[@@unboxed]letreciterfx=matchNODE.viewxwith|Empty->()|Leaf{key;value}->f.fkeyvalue|Branch{tree0;tree1;_}->iterftree0;iterftree1type('acc,'map)polyfold={f:'a.'aKey.t->('a,'map)Value.t->'acc->'acc}[@@unboxed]letrecfoldfmacc=matchNODE.viewmwith|Empty->acc|Leaf{key;value}->f.fkeyvalueacc|Branch{tree0;tree1;_}->letacc=foldftree0accinfoldftree1acctype('acc,'map)polyfold2={f:'a.'akey->('a,'map)value->('a,'map)value->'acc->'acc}[@@unboxed]letrecfold_on_nonequal_interftatbacc=ifta==tbthenaccelsematchNODE.viewta,NODE.viewtbwith|Empty,_|_,Empty->acc|Leaf{key;value},_->(tryletvalueb=findkeytbinifvalueb==valuethenaccelsef.fkeyvaluevaluebaccwithNot_found->acc)|_,Leaf{key;value}->(tryletvaluea=findkeytainifvaluea==valuethenaccelsef.fkeyvalueavalueaccwithNot_found->acc)|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: fold on each subtrees *)thenletacc=fold_on_nonequal_interfta0tb0accinletacc=fold_on_nonequal_interfta1tb1accinaccelseifbranches_beforepamapbmbthenif(ma:>int)land(pb:>int)==0thenfold_on_nonequal_interfta0tbaccelsefold_on_nonequal_interfta1tbaccelseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thenfold_on_nonequal_interftatb0accelsefold_on_nonequal_interftatb1accelseacctype('acc,'map)polyfold2_union={f:'a.'akey->('a,'map)valueoption->('a,'map)valueoption->'acc->'acc}[@@unboxed]letrecfold_on_nonequal_union:'m'acc.('acc,'m)polyfold2_union->'mt->'mt->'acc->'acc=fun(typem)f(ta:mt)(tb:mt)acc->ifta==tbthenaccelseletfleft:(_,_)polyfold={f=funkeyvalueacc->f.fkey(Somevalue)Noneacc}inletfright:(_,_)polyfold={f=funkeyvalueacc->f.fkeyNone(Somevalue)acc}inmatchNODE.viewta,NODE.viewtbwith|Empty,_->foldfrighttbacc|_,Empty->foldflefttaacc|Leaf{key;value},_->letida=Key.to_intkeyin(* Fold on the rest, knowing that ida may or may not be in b. So we fold and use
did_a to remember if we already did the call to a. *)letg(typeb)(keyb:bkey)(valueb:(b,m)value)(acc,did_a)=letdefault()=(f.fkeybNone(Somevalueb)acc,did_a)inifdid_athendefault()elseletidb=Key.to_intkeybinifunsigned_ltidbidathendefault()elseifunsigned_ltidaidbthenletacc=f.fkey(Somevalue)Noneaccinletacc=f.fkeybNone(Somevalueb)accin(acc,true)elsematchKey.polyeqkeykeybwith|Eq->ifvalue==valuebthen(acc,true)else(f.fkey(Somevalue)(Somevalueb)acc,true)|Diff->raise(Invalid_argument"Keys with same to_int value are not equal by polyeq")inlet(acc,found)=fold{f=funkeybvaluebacc->gkeybvaluebacc}tb(acc,false)iniffoundthenaccelsef.fkey(Somevalue)Noneacc|_,Leaf{key;value}->letidb=Key.to_intkeyinletg(typea)(keya:akey)(valuea:(a,m)value)(acc,did_b)=letdefault()=(f.fkeya(Somevaluea)Noneacc,did_b)inifdid_bthendefault()elseletida=Key.to_intkeyainifunsigned_ltidaidbthendefault()elseifunsigned_ltidbidathenletacc=f.fkeyNone(Somevalue)accinletacc=f.fkeya(Somevaluea)Noneaccin(acc,true)elsematchKey.polyeqkeyakeywith|Eq->ifvaluea==valuethen(acc,true)else(f.fkeya(Somevaluea)(Somevalue)acc,true)|Diff->raise(Invalid_argument"Keys with same to_int value are not equal by polyeq")inlet(acc,found)=fold{f=funkeyavalueaacc->gkeyavalueaacc}ta(acc,false)iniffoundthenaccelsef.fkeyNone(Somevalue)acc|Branch{prefix=pa;branching_bit=ma;tree0=ta0;tree1=ta1},Branch{prefix=pb;branching_bit=mb;tree0=tb0;tree1=tb1}->ifma==mb&&pa==pb(* Same prefix: merge the subtrees *)thenletacc=fold_on_nonequal_unionfta0tb0accinletacc=fold_on_nonequal_unionfta1tb1accinaccelseifbranches_beforepamapbmbthenif(ma:>int)land(pb:>int)==0thenletacc=fold_on_nonequal_unionfta0tbaccinletacc=foldfleftta1accinaccelseletacc=foldfleftta0accinletacc=fold_on_nonequal_unionfta1tbaccinaccelseifbranches_beforepbmbpamathenif(mb:>int)land(pa:>int)==0thenletacc=fold_on_nonequal_unionftatb0accinletacc=foldfrighttb1accinaccelseletacc=foldfrighttb0accinletacc=fold_on_nonequal_unionftatb1accinaccelse(* Distinct subtrees: process them in increasing order of keys. *)ifunsigned_lt(pa:>int)(pb:>int)thenletacc=foldflefttaaccinletacc=foldfrighttbaccinaccelseletacc=foldfrighttbaccinletacc=foldflefttaaccinacctype'mappolypredicate={f:'a.'akey->('a,'map)value->bool;}[@@unboxed]letfilterfm=filter_map{f=funkv->iff.fkvthenSomevelseNone}mletrecfor_allfm=matchNODE.viewmwith|Empty->true|Leaf{key;value}->f.fkeyvalue|Branch{tree0;tree1;_}->for_allftree0&&for_allftree1letrecto_seqm()=matchNODE.viewmwith|Empty->Seq.Nil|Leaf{key;value}->Seq.Cons(KeyValue(key,value),Seq.empty)|Branch{tree0;tree1;_}->Seq.append(to_seqtree0)(to_seqtree1)()letrecto_rev_seqm()=matchNODE.viewmwith|Empty->Seq.Nil|Leaf{key;value}->Seq.Cons(KeyValue(key,value),Seq.empty)|Branch{tree0;tree1;_}->Seq.append(to_rev_seqtree1)(to_rev_seqtree0)()letrecadd_seq:typea.akey_value_pairSeq.t->at->at=funsm->matchs()with|Seq.Nil->m|Seq.Cons(KeyValue(key,value),s)->add_seqs(addkeyvaluem)letof_seqs=add_seqsemptyletof_listl=of_seq(List.to_seql)letto_listm=List.of_seq(to_seqm)endmoduleMakeCustomHeterogeneousSet(Key:HETEROGENEOUS_KEY)(Node:NODEwithtype'akey='aKey.tandtype('a,'b)value=unit):HETEROGENEOUS_SETwithtype'aelt='aKey.tandtype'aBaseMap.t='aNode.t=structmoduleBaseMap=MakeCustomHeterogeneousMap(Key)(structtype('a,'b)t=unitend)(Node)(* No need to differentiate the values. *)includeBaseMaptypet=unitBaseMap.ttype'aelt='akeytypeany_elt=Any:'aelt->any_elt(* Note: as add is simpler, without any insertion function needed,
maybe it is worth reimplementing it. *)let[@specialise]addkeymap=BaseMap.addkey()mapletsingletonelt=singletonelt()letis_singletonset=matchBaseMap.is_singletonsetwith|None->None|Some(KeyValue(k,()))->Some(Any(k))(* Likewise with union and inter: we do not have to worry about
reconciling the values here, so we could reimplement if the
compiler is not smart enough. *)letunion=letf:(unit,unit,unit)BaseMap.polyunion={f=fun_()()->()}infun[@specialise]sasb->BaseMap.idempotent_unionfsasbletinter=letf:(unit,unit,unit)BaseMap.polyinter={f=fun_()()->()}infun[@specialise]sasb->(BaseMap.idempotent_inter(* [@specialised] *))fsasbtypepolyiter={f:'a.'aelt->unit;}[@@unboxed]letiterfset=BaseMap.iter{f=funk()->f.fk}set(* TODO: A real implementation of fold would be faster. *)type'accpolyfold={f:'a.'akey->'acc->'acc}[@@unboxed]letfoldfsetacc=letf:typea.akey->unit->'acc->'acc=funk()acc->f.fkaccinBaseMap.fold{f}setaccletunsigned_min_eltt=letKeyValue(m,())=BaseMap.unsigned_min_bindingtinAnymletunsigned_max_eltt=letKeyValue(m,())=BaseMap.unsigned_max_bindingtinAnymletmin_elt_inters1s2=BaseMap.min_binding_inters1s2|>Option.map(fun(KeyValueValue(m,(),()))->Anym)letmax_elt_inters1s2=BaseMap.min_binding_inters1s2|>Option.map(fun(KeyValueValue(m,(),()))->Anym)letpop_unsigned_maximumt=Option.map(fun(KeyValue(m,()),t)->Anym,t)(BaseMap.pop_unsigned_maximumt)letpop_unsigned_minimumt=Option.map(fun(KeyValue(m,()),t)->Anym,t)(BaseMap.pop_unsigned_minimumt)typepolypretty={f:'a.Format.formatter->'akey->unit;}[@@unboxed]letpretty?pp_sepffmts=BaseMap.pretty?pp_sep{f=funfmtk()->f.ffmtk}fmtsletequalt1t2=BaseMap.reflexive_same_domain_for_all2{f=fun___->true}t1t2letsubsett1t2=BaseMap.reflexive_subset_domain_for_all2{f=fun___->true}t1t2letdiff=BaseMap.difference{f=fun_()()->None}letsplitkm=let(l,present,r)=BaseMap.splitkmin(l,Option.is_somepresent,r)typepolypredicate={f:'a.'akey->bool;}[@@unboxed]letfilterfs=BaseMap.filter{f=funk()->f.fk}sletfor_allfs=BaseMap.for_all{f=funk()->f.fk}sletto_seqm=Seq.map(fun(KeyValue(elt,()))->Anyelt)(BaseMap.to_seqm)letto_rev_seqm=Seq.map(fun(KeyValue(elt,()))->Anyelt)(BaseMap.to_rev_seqm)letadd_seqsm=BaseMap.add_seq(Seq.map(fun(Anyelt)->KeyValue(elt,()))s)mletof_seqs=add_seqsemptyletof_listl=of_seq(List.to_seql)letto_lists=List.of_seq(to_seqs)letcompares1s2=BaseMap.reflexive_compare{f=fun_()()->0}s1s2endmoduleMakeHeterogeneousMap(Key:HETEROGENEOUS_KEY)(Value:HETEROGENEOUS_VALUE)=MakeCustomHeterogeneousMap(Key)(Value)(SimpleNode(Key)(Value))moduleMakeHeterogeneousSet(Key:HETEROGENEOUS_KEY)=MakeCustomHeterogeneousSet(Key)(SetNode(Key))moduleMakeCustomMap(Key:KEY)(Value:VALUE)(NODE:NODEwithtype'akey=Key.tandtype('key,'map)value=('key,'mapValue.t)snd)=structmoduleNewKey(* :Key *)=HeterogeneousKeyFromKey(Key)moduleBaseMap=MakeCustomHeterogeneousMap(NewKey)(structtype('key,'map)t=('key,'mapValue.t)sndend)(NODE)includeBaseMaptypekey=Key.ttype'avalue='aValue.tletsnd_opt=function|None->None|Somex->Some(Sndx)letopt_snd=function|None->None|Some(Sndx)->Somexletsingletonkv=singletonk(Sndv)letfindkm=letSndx=findkminxletfind_optkm=opt_snd(find_optkm)letinsertkfm=insertk(funv->Snd(f(opt_sndv)))mletupdatekfm=updatek(funv->snd_opt(f(opt_sndv)))mletaddkvm=addk(Sndv)mletsplitxm=let(l,m,r)=splitxmin(l,opt_sndm,r)letunsigned_min_bindingm=letKeyValue(key,Sndvalue)=BaseMap.unsigned_min_bindingminkey,valueletunsigned_max_bindingm=letKeyValue(key,Sndvalue)=BaseMap.unsigned_max_bindingminkey,valueletmin_binding_interm1m2=BaseMap.min_binding_interm1m2|>Option.map(fun(KeyValueValue(k,Sndv1,Sndv2))->(k,v1,v2))letmax_binding_interm1m2=BaseMap.max_binding_interm1m2|>Option.map(fun(KeyValueValue(k,Sndv1,Sndv2))->(k,v1,v2))(* let singleton k v = BaseMap.singleton (PolyKey.K k) v *)letpop_unsigned_minimumm=matchBaseMap.pop_unsigned_minimummwith|None->None|Some(KeyValue(key,Sndvalue),m)->Some(key,value,m)letpop_unsigned_maximumm=matchBaseMap.pop_unsigned_maximummwith|None->None|Some(KeyValue(key,Sndvalue),m)->Some(key,value,m)letis_singletonm=matchBaseMap.is_singletonmwith|None->None|Some(KeyValue(k,Sndv))->Some(k,v)letfilter(f:key->'avalue->bool)m=BaseMap.filter{f=funk(Sndv)->fkv}mletmapfa=BaseMap.map{f=fun(Sndv)->Snd(fv)}aletmap_no_sharefa=BaseMap.map_no_share{f=fun(Sndv)->Snd(fv)}aletmapi(f:key->'avalue->'avalue)a=BaseMap.mapi{f=funk(Sndv)->Snd(fkv)}aletmapi_no_share(f:key->'avalue->'bvalue)a=BaseMap.mapi_no_share{f=funk(Sndv)->Snd(fkv)}aletfilter_map(f:key->'avalue->'avalueoption)a=BaseMap.filter_map{f=funk(Sndv)->snd_opt(fkv)}aletfilter_map_no_share(f:key->'avalue->'bvalueoption)a=BaseMap.filter_map_no_share{f=funk(Sndv)->snd_opt(fkv)}aletidempotent_union(f:key->'avalue->'avalue->'avalue)ab=BaseMap.idempotent_union{f=funk(Sndv1)(Sndv2)->Snd(fkv1v2)}abletidempotent_inter(f:key->'avalue->'avalue->'avalue)ab=BaseMap.idempotent_inter{f=funk(Sndv1)(Sndv2)->Snd(fkv1v2)}abletnonidempotent_inter_no_share(f:key->'avalue->'bvalue->'cvalue)ab=BaseMap.nonidempotent_inter_no_share{f=funk(Sndv1)(Sndv2)->Snd(fkv1v2)}abletidempotent_inter_filter(f:key->'avalue->'avalue->'avalueoption)ab=BaseMap.idempotent_inter_filter{f=funk(Sndv1)(Sndv2)->snd_opt(fkv1v2)}abletreflexive_same_domain_for_all2(f:key->'avalue->'avalue->bool)ab=BaseMap.reflexive_same_domain_for_all2{f=funk(Sndv1)(Sndv2)->fkv1v2}abletnonreflexive_same_domain_for_all2(f:key->'avalue->'bvalue->bool)ab=BaseMap.nonreflexive_same_domain_for_all2{f=funk(Sndv1)(Sndv2)->fkv1v2}abletreflexive_subset_domain_for_all2(f:key->'avalue->'avalue->bool)ab=BaseMap.reflexive_subset_domain_for_all2{f=funk(Sndv1)(Sndv2)->fkv1v2}abletslow_merge(f:key->'avalueoption->'bvalueoption->'cvalueoption)ab=BaseMap.slow_merge{f=funkv1v2->snd_opt(fk(opt_sndv1)(opt_sndv2))}abletsymmetric_difference(f:key->'avalue->'avalue->'avalueoption)ab=BaseMap.symmetric_difference{f=funk(Sndv1)(Sndv2)->snd_opt(fkv1v2)}abletdifference(f:key->'avalue->'bvalue->'avalueoption)ab=BaseMap.difference{f=funk(Sndv1)(Sndv2)->snd_opt(fkv1v2)}abletiter(f:key->'avalue->unit)a=BaseMap.iter{f=funk(Sndv)->fkv}aletfold(f:key->'avalue->'acc->'acc)macc=BaseMap.fold{f=funk(Sndv)acc->fkvacc}maccletfold_on_nonequal_inter(f:key->'avalue->'avalue->'acc->'acc)mambacc=letfk(Sndva)(Sndvb)acc=fkvavbaccinBaseMap.fold_on_nonequal_inter{f}mambaccletfold_on_nonequal_union(f:key->'avalueoption->'avalueoption->'acc->'acc)mambacc=letfkvavbacc=letva=Option.map(fun(Sndv)->v)vainletvb=Option.map(fun(Sndv)->v)vbinfkvavbaccinBaseMap.fold_on_nonequal_union{f}mambaccletpretty?pp_sep(f:Format.formatter->key->'avalue->unit)fmtm=BaseMap.pretty?pp_sep{f=funfmtk(Sndv)->ffmtkv}fmtmletfor_all(f:key->'avalue->bool)m=BaseMap.for_all{f=funk(Sndv)->fkv}mmoduleWithForeign(Map2:NODE_WITH_FINDwithtype_key=key)=structmoduleBaseForeign=BaseMap.WithForeign(Map2)type('b,'c)polyfilter_map_foreign={f:'a.key->('a,'b)Map2.value->'cvalueoption}[@@unboxed]letfilter_map_no_sharefm2=BaseForeign.filter_map_no_share{f=funkv->snd_opt(f.fkv)}m2type('value,'map2)polyinter_foreign={f:'a.'aMap2.key->'valuevalue->('a,'map2)Map2.value->'valuevalue}[@@unboxed]letnonidempotent_interfm1m2=BaseForeign.nonidempotent_inter{f=funk(Sndv)v2->Snd(f.fkvv2)}m1m2type('map1,'map2)polyupdate_multiple={f:'a.key->'map1valueoption->('a,'map2)Map2.value->'map1valueoption}[@@unboxed]letupdate_multiple_from_foreignm2fm=BaseForeign.update_multiple_from_foreignm2{f=funkv1v2->snd_opt(f.fk(opt_sndv1)v2)}mtype('map1,'map2)polyupdate_multiple_inter={f:'a.key->'map1value->('a,'map2)Map2.value->'map1valueoption}[@@unboxed]letupdate_multiple_from_inter_with_foreignm2fm=BaseForeign.update_multiple_from_inter_with_foreignm2{f=funk(Sndv1)v2->snd_opt(f.fkv1v2)}mtype('map1,'map2)polydifference=('map1,'map2)polyupdate_multiple_interletdifferencefm1m2=BaseForeign.difference{f=funk(Sndv)v2->snd_opt(f.fkvv2)}m1m2endletto_seqm=Seq.map(fun(KeyValue(key,Sndvalue))->(key,value))(BaseMap.to_seqm)letto_rev_seqm=Seq.map(fun(KeyValue(key,Sndvalue))->(key,value))(BaseMap.to_rev_seqm)letadd_seqsm=BaseMap.add_seq(Seq.map(fun(key,value)->KeyValue(key,Sndvalue))s)mletof_seqs=add_seqsemptyletof_listl=of_seq(List.to_seql)letto_lists=List.of_seq(to_seqs)letreflexive_equalfm1m2=reflexive_same_domain_for_all2(fun_->f)m1m2letreflexive_comparefm1m2=reflexive_compare{f=fun_(Sndv1)(Sndv2)->fv1v2}m1m2endmoduleMakeMap(Key:KEY)=structmoduleNKey=structtype'at=Key.tendmoduleNode=SimpleNode(NKey)(WrappedHomogeneousValue)includeMakeCustomMap(Key)(Value)(Node)endmoduleMakeCustomSet(Key:KEY)(Node:NODEwithtype'akey=Key.tandtype('key,'map)value=unit):SETwithtypeelt=Key.tandtype'aBaseMap.t='aNode.t=structmoduleHKey=HeterogeneousKeyFromKey(Key)moduleS=MakeCustomHeterogeneousSet(HKey)(Node)includeStypekey=Key.ttypeelt=keyletiter(f:elt->unit)set=S.iter{f}setletfold(f:key->'acc->'acc)setacc=S.fold{f}setaccletfilter(f:key->bool)set=S.filter{f}setletfor_all(f:key->bool)set=S.for_all{f}setletpretty?pp_sep(f:Format.formatter->key->unit)fmts=S.pretty?pp_sep{f}fmtsletis_singletonm=matchBaseMap.is_singletonmwith|None->None|Some(KeyValue(k,()))->Somekletunsigned_min_eltt=letAnyx=unsigned_min_elttinxletunsigned_max_eltt=letAnyx=unsigned_max_elttinxletpop_unsigned_minimumt=Option.map(fun(Anyx,t)->(x,t))(pop_unsigned_minimumt)letpop_unsigned_maximumt=Option.map(fun(Anyx,t)->(x,t))(pop_unsigned_maximumt)letmin_elt_intert1t2=Option.map(fun(Anyx)->x)(min_elt_intert1t2)letmax_elt_intert1t2=Option.map(fun(Anyx)->x)(max_elt_intert1t2)letto_seqm=Seq.map(fun(BaseMap.KeyValue(elt,()))->elt)(BaseMap.to_seqm)letto_rev_seqm=Seq.map(fun(BaseMap.KeyValue(elt,()))->elt)(BaseMap.to_rev_seqm)letadd_seqsm=BaseMap.add_seq(Seq.map(fun(elt)->BaseMap.KeyValue(elt,()))s)mletof_seqs=add_seqsemptyletof_listl=of_seq(List.to_seql)letto_lists=List.of_seq(to_seqs)endmoduleMakeSet(Key:KEY)=MakeCustomSet(Key)(SetNode(HeterogeneousKeyFromKey(Key)))moduleMakeHashconsedHeterogeneousMap(Key:HETEROGENEOUS_KEY)(Value:HETEROGENEOUS_HASHED_VALUE)()=structmoduleNode=HashconsedNode(Key)(Value)()includeMakeCustomHeterogeneousMap(Key)(Value)(Node)letequal=Node.equalletcompare=Node.compareletto_int=Node.to_intendmoduleMakeHashconsedHeterogeneousSet(Key:HETEROGENEOUS_KEY)()=structmoduleNode=HashconsedSetNode(Key)()includeMakeCustomHeterogeneousSet(Key)(Node)letequal=Node.equalletcompare=Node.compareletto_int=Node.to_intendmoduleMakeHashconsedSet(Key:KEY)()=structmoduleNode=HashconsedSetNode(HeterogeneousKeyFromKey(Key))()includeMakeCustomSet(Key)(Node)letequal=Node.equalletcompare=Node.compareletto_int=Node.to_intendmoduleMakeHashconsedMap(Key:KEY)(Value:HASHED_VALUE)()=structmoduleHetValue=HeterogeneousHashedValueFromHashedValue(Value)moduleNode=HashconsedNode(HeterogeneousKeyFromKey(Key))(HetValue)()includeMakeCustomMap(Key)(Value)(Node)letequal=Node.equalletcompare=Node.compareletto_int=Node.to_intend