123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765(*
This file is derived from the map.ml file from the OCaml distribution.
Changes are marked with the [MOPSA] symbol.
Modifications are Copyright (C) 2017-2019 The MOPSA Project.
Original copyright follows.
*)(***********************************************************************)(* *)(* Objective Caml *)(* *)(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)(* *)(* Copyright 1996 Institut National de Recherche en Informatique et *)(* en Automatique. All rights reserved. This file is distributed *)(* under the terms of the GNU Library General Public License, with *)(* the special exception on linking described in file ../LICENSE. *)(* *)(***********************************************************************)(* [MOPSA] module signatures moved to a separate file *)openMapExtSigmoduleMake(Ord:OrderedType)=structtypekey=Ord.ttype'at=Empty|Nodeof'at*key*'a*'at*intletheight=functionEmpty->0|Node(_,_,_,_,h)->hletcreatelxdr=lethl=heightlandhr=heightrinNode(l,x,d,r,(ifhl>=hrthenhl+1elsehr+1))letsingletonxd=Node(Empty,x,d,Empty,1)letballxdr=lethl=matchlwithEmpty->0|Node(_,_,_,_,h)->hinlethr=matchrwithEmpty->0|Node(_,_,_,_,h)->hinifhl>hr+2thenbeginmatchlwithEmpty->invalid_arg"Mapext.bal"|Node(ll,lv,ld,lr,_)->ifheightll>=heightlrthencreatelllvld(createlrxdr)elsebeginmatchlrwithEmpty->invalid_arg"Mapext.bal"|Node(lrl,lrv,lrd,lrr,_)->create(createlllvldlrl)lrvlrd(createlrrxdr)endendelseifhr>hl+2thenbeginmatchrwithEmpty->invalid_arg"Mapext.bal"|Node(rl,rv,rd,rr,_)->ifheightrr>=heightrlthencreate(createlxdrl)rvrdrrelsebeginmatchrlwithEmpty->invalid_arg"Mapext.bal"|Node(rll,rlv,rld,rlr,_)->create(createlxdrll)rlvrld(createrlrrvrdrr)endendelseNode(l,x,d,r,(ifhl>=hrthenhl+1elsehr+1))letempty=Emptyletis_empty=functionEmpty->true|_->falseletrecaddxdatam=matchmwithEmpty->Node(Empty,x,data,Empty,1)|Node(l,v,d,r,h)->letc=Ord.comparexvinifc=0thenifd==datathenmelseNode(l,x,data,r,h)elseifc<0thenletll=addxdatalinifl==llthenmelseballlvdrelseletrr=addxdatarinifr==rrthenmelseballvdrrletrecfindx=functionEmpty->raiseNot_found|Node(l,v,d,r,_)->letc=Ord.comparexvinifc=0thendelsefindx(ifc<0thenlelser)letrecfind_optx=functionEmpty->None|Node(l,v,d,r,_)->letc=Ord.comparexvinifc=0thenSomedelsefind_optx(ifc<0thenlelser)letrecmemx=functionEmpty->false|Node(l,v,d,r,_)->letc=Ord.comparexvinc=0||memx(ifc<0thenlelser)letrecmin_binding=functionEmpty->raiseNot_found|Node(Empty,x,d,r,_)->(x,d)|Node(l,x,d,r,_)->min_bindinglletrecmax_binding=functionEmpty->raiseNot_found|Node(l,x,d,Empty,_)->(x,d)|Node(l,x,d,r,_)->max_bindingrletrecremove_min_binding=functionEmpty->invalid_arg"Mapext.remove_min_elt"|Node(Empty,x,d,r,_)->r|Node(l,x,d,r,_)->bal(remove_min_bindingl)xdrletmerget1t2=match(t1,t2)with(Empty,t)->t|(t,Empty)->t|(_,_)->let(x,d)=min_bindingt2inbalt1xd(remove_min_bindingt2)letrecremovexm=matchmwithEmpty->Empty|Node(l,v,d,r,h)->letc=Ord.comparexvinifc=0thenmergelrelseifc<0thenletll=removexlinifl==llthenmelseballlvdrelseletrr=removexrinifr==rrthenmelseballvdrrletreciterf=functionEmpty->()|Node(l,v,d,r,_)->iterfl;fvd;iterfrletrecmapf=functionEmpty->Empty|Node(l,v,d,r,h)->letl'=mapflinletd'=fdinletr'=mapfrinNode(l',v,d',r',h)letrecmapif=functionEmpty->Empty|Node(l,v,d,r,h)->letl'=mapiflinletd'=fvdinletr'=mapifrinNode(l',v,d',r',h)letrecfoldfmaccu=matchmwithEmpty->accu|Node(l,v,d,r,_)->foldfr(fvd(foldflaccu))(* [MOPSA] changed to call p in the key order *)letrecfor_allp=functionEmpty->true|Node(l,v,d,r,_)->for_allpl&&pvd&&for_allpr(* [MOPSA] changed to call p in the key order *)letrecexistsp=functionEmpty->false|Node(l,v,d,r,_)->existspl||pvd||existspr(* [MOPSA] changed to call p in the key order *)letfilterps=fold(funkda->ifpkdthenaddkdaelsea)sEmptyletpartitionps=letrecpart(t,fasaccu)=function|Empty->accu|Node(l,v,d,r,_)->part(part(ifpvdthen(addvdt,f)else(t,addvdf))l)rinpart(Empty,Empty)s(* Same as create and bal, but no assumptions are made on the
relative heights of l and r. *)letrecjoinlvdr=match(l,r)with(Empty,_)->addvdr|(_,Empty)->addvdl|(Node(ll,lv,ld,lr,lh),Node(rl,rv,rd,rr,rh))->iflh>rh+2thenballllvld(joinlrvdr)elseifrh>lh+2thenbal(joinlvdrl)rvrdrrelsecreatelvdr(* Merge two trees l and r into one.
All elements of l must precede the elements of r.
No assumption on the heights of l and r. *)letconcatt1t2=match(t1,t2)with(Empty,t)->t|(t,Empty)->t|(_,_)->let(x,d)=min_bindingt2injoint1xd(remove_min_bindingt2)letconcat_or_joint1vdt2=matchdwith|Somed->joint1vdt2|None->concatt1t2letrecsplitx=functionEmpty->(Empty,None,Empty)|Node(l,v,d,r,_)->letc=Ord.comparexvinifc=0then(l,Somed,r)elseifc<0thenlet(ll,pres,rl)=splitxlin(ll,pres,joinrlvdr)elselet(lr,pres,rr)=splitxrin(joinlvdlr,pres,rr)letrecmergefs1s2=match(s1,s2)with(Empty,Empty)->Empty|(Node(l1,v1,d1,r1,h1),_)whenh1>=heights2->let(l2,d2,r2)=splitv1s2inconcat_or_join(mergefl1l2)v1(fv1(Somed1)d2)(mergefr1r2)|(_,Node(l2,v2,d2,r2,h2))->let(l1,d1,r1)=splitv2s1inconcat_or_join(mergefl1l2)v2(fv2d1(Somed2))(mergefr1r2)|_->assertfalsetype'aenumeration=End|Moreofkey*'a*'at*'aenumerationletreccons_enumme=matchmwithEmpty->e|Node(l,v,d,r,_)->cons_enuml(More(v,d,r,e))(* We replace the original equal by one based on iter2zo.
This assumes that cmp x x returns 0.
*)(*
let compare cmp m1 m2 =
let rec compare_aux e1 e2 =
match (e1, e2) with
(End, End) -> 0
| (End, _) -> -1
| (_, End) -> 1
| (More(v1, d1, r1, e1), More(v2, d2, r2, e2)) ->
let c = Ord.compare v1 v2 in
if c <> 0 then c else
let c = cmp d1 d2 in
if c <> 0 then c else
compare_aux (cons_enum r1 e1) (cons_enum r2 e2)
in compare_aux (cons_enum m1 End) (cons_enum m2 End)
*)(* We replace the original equal by one based on iter2zo.
This assumes that cmp x x returns true.
*)(*
let equal cmp m1 m2 =
let rec equal_aux e1 e2 =
match (e1, e2) with
(End, End) -> true
| (End, _) -> false
| (_, End) -> false
| (More(v1, d1, r1, e1), More(v2, d2, r2, e2)) ->
Ord.compare v1 v2 = 0 && cmp d1 d2 &&
equal_aux (cons_enum r1 e1) (cons_enum r2 e2)
in equal_aux (cons_enum m1 End) (cons_enum m2 End)
*)letreccardinal=functionEmpty->0|Node(l,_,_,r,_)->cardinall+1+cardinalrletrecbindings_auxaccu=functionEmpty->accu|Node(l,v,d,r,_)->bindings_aux((v,d)::bindings_auxaccur)lletbindingss=bindings_aux[]sletchoose=min_binding(* [MOPSA] additions *)(* ***************** *)letis_singleton=function|Node(Empty,_,_,Empty,_)->true|_->falseletof_listl=List.fold_left(funacc(k,x)->addkxacc)emptyl(* internal function *)(* similar to split, but returns unbalanced trees *)letreccutk=functionEmpty->Empty,None,Empty|Node(l1,k1,d1,r1,h1)->letc=Ord.comparekk1inifc<0thenletl2,d2,r2=cutkl1in(l2,d2,Node(r2,k1,d1,r1,h1))elseifc>0thenletl2,d2,r2=cutkr1in(Node(l1,k1,d1,l2,h1),d2,r2)else(l1,Somed1,r1)(* binary operations that fail on maps with different keys *)(* functions are called in increasing key order *)letrecmap2fm1m2=matchm1with|Empty->ifm2=EmptythenEmptyelseinvalid_arg"Mapext.map2"|Node(l1,k,d1,r1,h1)->matchcutkm2with|l2,Somed2,r2->Node(map2fl1l2,k,fkd1d2,map2fr1r2,h1)|_,None,_->invalid_arg"Mapext.map2"letreciter2fm1m2=matchm1with|Empty->ifm2=Emptythen()elseinvalid_arg"Mapext.iter2"|Node(l1,k,d1,r1,h1)->matchcutkm2with|l2,Somed2,r2->iter2fl1l2;fkd1d2;iter2fr1r2|_,None,_->invalid_arg"Mapext.iter2"letrecfold2fm1m2acc=matchm1with|Empty->ifm2=Emptythenaccelseinvalid_arg"Mapext.fold2"|Node(l1,k,d1,r1,h1)->matchcutkm2with|l2,Somed2,r2->fold2fr1r2(fkd1d2(fold2fl1l2acc))|_,None,_->invalid_arg"Mapext.fold2"letrecfor_all2fm1m2=matchm1with|Empty->ifm2=Emptythentrueelseinvalid_arg"Mapext.for_all2"|Node(l1,k,d1,r1,h1)->matchcutkm2with|l2,Somed2,r2->for_all2fl1l2&&fkd1d2&&for_all2fr1r2|_,None,_->invalid_arg"Mapext.for_all2"letrecexists2fm1m2=matchm1with|Empty->ifm2=Emptythenfalseelseinvalid_arg"Mapext.exists2"|Node(l1,k,d1,r1,h1)->matchcutkm2with|l2,Somed2,r2->exists2fl1l2||fkd1d2||exists2fr1r2|_,None,_->invalid_arg"Mapext.exists2"(* as above, but ignore physically equal subtrees
- for map, assumes: f k d d = d
- for iter, assumes: f k d d has no effect
- for fold, assumes: k f d d acc = acc
- for for_all, assumes: f k d d = true
- for exists, assumes: f k d d = false
*)letrecmap2zfm1m2=ifm1==m2thenm1elsematchm1with|Empty->ifm2=EmptythenEmptyelseinvalid_arg"Mapext.map2z"|Node(l1,k,d1,r1,h1)->matchcutkm2with|l2,Somed2,r2->letd=ifd1==d2thend1elsefkd1d2inNode(map2zfl1l2,k,d,map2zfr1r2,h1)|_,None,_->invalid_arg"Mapext.map2z"letreciter2zfm1m2=ifm1==m2then()elsematchm1with|Empty->ifm2=Emptythen()elseinvalid_arg"Mapext.iter2z"|Node(l1,k,d1,r1,h1)->matchcutkm2with|l2,Somed2,r2->iter2zfl1l2;(ifd1!=d2thenfkd1d2);iter2zfr1r2|_,None,_->invalid_arg"Mapext.iter2z"letrecfold2zfm1m2acc=ifm1==m2thenaccelsematchm1with|Empty->ifm2=Emptythenaccelseinvalid_arg"Mapext.fold2z"|Node(l1,k,d1,r1,h1)->matchcutkm2with|l2,Somed2,r2->letacc=fold2zfl1l2accinletacc=ifd1==d2thenaccelsefkd1d2accinfold2zfr1r2acc|_,None,_->invalid_arg"Mapext.fold2z"letrecfor_all2zfm1m2=(m1==m2)||(matchm1with|Empty->ifm2=Emptythentrueelseinvalid_arg"Mapext.for_all2z"|Node(l1,k,d1,r1,h1)->matchcutkm2with|l2,Somed2,r2->(for_all2zfl1l2)&&(d1==d2||fkd1d2)&&(for_all2zfr1r2)|_,None,_->invalid_arg"Mapext.for_all2z")letrecexists2zfm1m2=(m1!=m2)&&(matchm1with|Empty->ifm2=Emptythenfalseelseinvalid_arg"Mapext.exists2z"|Node(l1,k,d1,r1,h1)->matchcutkm2with|l2,Somed2,r2->(exists2zfl1l2)||(d1!=d2&&fkd1d2)||(exists2zfr1r2)|_,None,_->invalid_arg"Mapext.exists2z")(* as above, but allow maps with different keys *)letrecmap2of1f2fm1m2=matchm1with|Empty->mapif2m2|Node(l1,k,d1,r1,h1)->letl2,d2,r2=cutkm2inletl=map2of1f2fl1l2inletd=matchd2withNone->f1kd1|Somed2->fkd1d2inletr=map2of1f2fr1r2injoinlkdrletreciter2of1f2fm1m2=matchm1with|Empty->iterf2m2|Node(l1,k,d1,r1,h1)->letl2,d2,r2=cutkm2initer2of1f2fl1l2;(matchd2withNone->f1kd1|Somed2->fkd1d2);iter2of1f2fr1r2letrecfold2of1f2fm1m2acc=matchm1with|Empty->foldf2m2acc|Node(l1,k,d1,r1,h1)->letl2,d2,r2=cutkm2inletacc=fold2of1f2fl1l2accinletacc=matchd2with|None->f1kd1acc|Somed2->fkd1d2accinfold2of1f2fr1r2accletrecfor_all2of1f2fm1m2=matchm1with|Empty->for_allf2m2|Node(l1,k,d1,r1,h1)->letl2,d2,r2=cutkm2in(for_all2of1f2fl1l2)&&(matchd2withNone->f1kd1|Somed2->fkd1d2)&&(for_all2of1f2fr1r2)letrecexists2of1f2fm1m2=matchm1with|Empty->existsf2m2|Node(l1,k,d1,r1,h1)->letl2,d2,r2=cutkm2in(exists2of1f2fl1l2)||(matchd2withNone->f1kd1|Somed2->fkd1d2)||(exists2of1f2fr1r2)(* all together now *)letrecmap2zof1f2fm1m2=ifm1==m2thenm1elsematchm1with|Empty->mapif2m2|Node(l1,k,d1,r1,h1)->letl2,d2,r2=cutkm2inletl=map2zof1f2fl1l2inletd=matchd2with|None->f1kd1|Somed2->ifd1==d2thend1elsefkd1d2inletr=map2zof1f2fr1r2injoinlkdrletreciter2zof1f2fm1m2=ifm1==m2then()elsematchm1with|Empty->iterf2m2|Node(l1,k,d1,r1,h1)->letl2,d2,r2=cutkm2initer2zof1f2fl1l2;(matchd2with|None->f1kd1|Somed2->ifd1!=d2thenfkd1d2);iter2zof1f2fr1r2letrecfold2zof1f2fm1m2acc=ifm1==m2thenaccelsematchm1with|Empty->foldf2m2acc|Node(l1,k,d1,r1,h1)->letl2,d2,r2=cutkm2inletacc=fold2zof1f2fl1l2accinletacc=matchd2with|None->f1kd1acc|Somed2->ifd1==d2thenaccelsefkd1d2accinfold2zof1f2fr1r2accletrecfor_all2zof1f2fm1m2=(m1==m2)||(matchm1with|Empty->for_allf2m2|Node(l1,k,d1,r1,h1)->letl2,d2,r2=cutkm2in(for_all2zof1f2fl1l2)&&(matchd2withNone->f1kd1|Somed2->d1==d2||fkd1d2)&&(for_all2zof1f2fr1r2))letrecexists2zof1f2fm1m2=(m1!=m2)&&(matchm1with|Empty->existsf2m2|Node(l1,k,d1,r1,h1)->letl2,d2,r2=cutkm2in(exists2zof1f2fl1l2)||(matchd2withNone->f1kd1|Somed2->d1!=d2&&fkd1d2)||(exists2zof1f2fr1r2))letequalcmpm1m2=tryiter2zo(fun__->raiseExit)(fun__->raiseExit)(fun_xy->ifnot(cmpxy)thenraiseExit)m1m2;truewithExit->falseletcomparecmpm1m2=letr=ref0intryiter2zo(fun__->r:=1;raiseExit)(fun__->r:=-1;raiseExit)(fun_xy->r:=cmpxy;if!r<>0thenraiseExit)m1m2;!rwithExit->!r(* iterators limited to keys between two bounds *)letrecmap_slicefmlohi=matchmwith|Empty->Empty|Node(l,k,d,r,h)->letc1,c2=Ord.compareklo,Ord.comparekhiinletl=ifc1>0thenmap_slicefllohielselinletd=ifc1>=0&&c2<=0thenfkdelsedinletr=ifc2<0thenmap_slicefrlohielserinNode(l,k,d,r,h)letreciter_slicefmlohi=matchmwith|Empty->()|Node(l,k,d,r,_)->letc1,c2=Ord.compareklo,Ord.comparekhiinifc1>0theniter_slicefllohi;ifc1>=0&&c2<=0thenfkd;ifc2<0theniter_slicefrlohiletrecfold_slicefmlohiacc=matchmwith|Empty->acc|Node(l,k,d,r,_)->letc1,c2=Ord.compareklo,Ord.comparekhiinletacc=ifc1>0thenfold_slicefllohiaccelseaccinletacc=ifc1>=0&&c2<=0thenfkdaccelseaccinifc2<0thenfold_slicefrlohiaccelseaccletrecfor_all_slicefmlohi=matchmwith|Empty->true|Node(l,k,d,r,_)->letc1,c2=Ord.compareklo,Ord.comparekhiin(c1<=0||for_all_slicefllohi)&&(c1<0||c2>0||fkd)&&(c2>=0||for_all_slicefrlohi)letrecexists_slicefmlohi=matchmwith|Empty->false|Node(l,k,d,r,_)->letc1,c2=Ord.compareklo,Ord.comparekhiin(c1>0&&exists_slicefllohi)||(c1>=0&&c2<=0&&fkd)||(c2<0&&exists_slicefrlohi)(* key set comparison *)letreckey_equalm1m2=(m1==m2)||(matchm1with|Empty->m2=Empty|Node(l1,k,_,r1,_)->matchcutkm2with|_,None,_->false|l2,Some_,r2->key_equall1l2&&key_equalr1r2)letreckey_subsetm1m2=(m1==m2)||(matchm1with|Empty->true|Node(l1,k,_,r1,_)->matchcutkm2with|_,None,_->false|l2,Some_,r2->key_subsetl1l2&&key_subsetr1r2)(* navigation *)letfind_greater_equalkm=letrecauxmfound=matchmwith|Empty->(matchfoundwithNone->raiseNot_found|Somex->x)|Node(l,kk,d,r,_)->letc=Ord.comparekkkinifc=0thenkk,delseifc>0thenauxrfoundelseauxl(Some(kk,d))inauxmNoneletfind_greaterkm=letrecauxmfound=matchmwith|Empty->(matchfoundwithNone->raiseNot_found|Somex->x)|Node(l,kk,d,r,_)->letc=Ord.comparekkkinifc>=0thenauxrfoundelseauxl(Some(kk,d))inauxmNoneletfind_less_equalkm=letrecauxmfound=matchmwith|Empty->(matchfoundwithNone->raiseNot_found|Somex->x)|Node(l,kk,d,r,_)->letc=Ord.comparekkkinifc=0thenkk,delseifc<0thenauxlfoundelseauxr(Some(kk,d))inauxmNoneletfind_lesskm=letrecauxmfound=matchmwith|Empty->(matchfoundwithNone->raiseNot_found|Somex->x)|Node(l,kk,d,r,_)->letc=Ord.comparekkkinifc<=0thenauxlfoundelseauxr(Some(kk,d))inauxmNone(* printing *)letprint_genoprinterkeyelemchs=ifs=Emptythenochprinter.print_emptyelse(letfirst=reftrueinochprinter.print_begin;iter(funke->if!firstthenfirst:=falseelseochprinter.print_sep;keychk;ochprinter.print_arrow;elemche)s;ochprinter.print_end)(* internal printing helper *)letprintprinterkeyelemchl=print_genoutput_stringprinterkeyelemchlletbprintprinterkeyelemchl=print_genBuffer.add_stringprinterkeyelemchlletfprintprinterkeyelemchl=print_gen(funfmts->Format.fprintffmt"%s"s)printerkeyelemchlletto_stringprinterkeyeleml=letb=Buffer.create10inprint_gen(fun()s->Buffer.add_stringbs)printer(fun()k->Buffer.add_stringb(keyk))(fun()e->Buffer.add_stringb(eleme))()l;Buffer.contentsb(* Translation to polymorphic maps *)letto_poly_mapm=MapExtPoly.of_listOrd.compare(bindingsm)endletprinter_default={print_empty="{}";print_begin="{";print_arrow=":";print_sep=";";print_end="}";}(** [MOPSA] Print as {key1:val1;key2:val2;...} *)(* [MOPSA] A few useful instances *)moduleStringMap=Make(String)moduleIntMap=Make(structtypet=intletcompare:int->int->int=compareend)moduleInt32Map=Make(Int32)moduleInt64Map=Make(Int64)moduleZMap=Make(Z)