123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865(* Portions Copyright (c) Meta Platforms, Inc. and affiliates. *)(***********************************************************************
* *
* 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. *
* *
***********************************************************************)(* This module has been inspired from the OCaml standard library.
* There are some modifications to make it run fast.
* - It adds a Leaf node to avoid excessive allocation for singleton set
* - In the hot [bal] function when we we know it has to be [Node], we do
* an unsafe cast to avoid some unneeded tests
* - Functions not need comparison functions are lifted outside functors
* - We can add more utilities relying on the internals in the future
*)moduletypeOrderedType=sigtypetvalcompare:t->t->intendmoduletypeS=sigtypeelttypetvalempty:tvalis_empty:t->boolvalmem:elt->t->boolvaladd:elt->t->tvalsingleton:elt->tvalremove:elt->t->tvalunion:t->t->tvalinter:t->t->tvaldisjoint:t->t->boolvaldiff:t->t->tvalcompare:t->t->intvalequal:t->t->boolvalsubset:t->t->boolvaliter:(elt->unit)->t->unitvalmap:(elt->elt)->t->tvalfold:(elt->'a->'a)->t->'a->'avalfor_all:(elt->bool)->t->boolvalexists:(elt->bool)->t->boolvalfilter:(elt->bool)->t->tvalpartition:(elt->bool)->t->t*tvalcardinal:t->intvalelements:t->eltlistvalmin_elt:t->eltvalmin_elt_opt:t->eltoptionvalmax_elt:t->eltvalmax_elt_opt:t->eltoptionvalchoose:t->eltvalchoose_opt:t->eltoptionvalfind:elt->t->eltvalfind_opt:elt->t->eltoptionvalto_seq:t->eltSeq.tvalof_list:eltlist->tvalmake_pp:(Format.formatter->elt->unit)->Format.formatter->t->unitvalof_increasing_iterator_unchecked:(unit->elt)->int->tvalof_sorted_array_unchecked:eltarray->tvalfind_first_opt:(elt->bool)->t->eltoptionendtype'eltt0=|Empty|Leafof'elt|Nodeof{h:int;v:'elt;l:'eltt0;r:'eltt0;}type'eltpartial_node={h:int;v:'elt;l:'eltt0;r:'eltt0;}external(~!):'eltt0->'eltpartial_node="%identity"type('elt,'t)enumeration0=|End|Moreof'elt*'t*('elt,'t)enumeration0letreccons_enumse=matchswith|Empty->e|Leafv->More(v,Empty,e)|Node{l;v;r;_}->cons_enuml(More(v,r,e))letrecseq_of_enum_c()=matchcwith|End->Seq.Nil|More(x,t,rest)->Seq.Cons(x,seq_of_enum_(cons_enumtrest))letto_seqc=seq_of_enum_(cons_enumcEnd)let[@inline]height=function|Empty->0|Leaf_->1|Node{h;_}->hlet[@inline]singletonx=Leafx(* FIXME: we should check to avoid creating unneeded Node
- node
- Node
This function produce Node of height at least [1]
*)letunsafe_node~l~v~r=match(l,r)with|(Empty,Empty)->singletonv|(Leaf_,Empty)|(Leaf_,Leaf_)|(Empty,Leaf_)->Node{l;v;r;h=2}|(Node{h;_},(Leaf_|Empty))|((Leaf_|Empty),Node{h;_})->Node{l;v;r;h=h+1}|(Node{h=hl;_},Node{h=hr;_})->leth=ifhl>=hrthenhl+1elsehr+1inNode{l;v;r;h}(* Creates a new node with left son l, value v and right son r.
We must have all elements of l < v < all elements of r.
l and r must be balanced and | height l - height r | <= 2.
Inline expansion of height for better speed. *)letcreatelvr=lethl=heightlinlethr=heightrinNode{l;v;r;h=(ifhl>=hrthenhl+1elsehr+1);}letrecof_increasing_iterator_uncheckedf=function|0->Empty|1->letv=f()inLeafv|n->letlenl=nlsr1inletlenr=n-lenl-1inletl=of_increasing_iterator_uncheckedflenlinletv=f()inletr=of_increasing_iterator_uncheckedflenrinNode{l;v;r;h=heightl+1}letof_sorted_array_uncheckedxs=letlen=Array.lengthxsinleti=ref0inletf()=letx=xs.(!i)inincri;xinof_increasing_iterator_uncheckedflen(* Same as create, but performs one step of rebalancing if necessary.
Assumes l and r balanced and | height l - height r | <= 3.
Inline expansion of create for better speed in the most frequent case
where no rebalancing is required. *)letballvr=lethl=heightlinlethr=heightrinifhl>hr+2then(* hl is at least of height > 2 [3], so it should be [Node]
Note having in-efficient nodes like [Node (empty,v,empty)] won't affect
correctness here, since it will be even more likely to be [Node]
But we are stricter with height
*)let{l=ll;v=lv;r=lr;_}=~!linifheightll>=heightlrthencreatelllv(unsafe_node~l:lr~v~r)else(* Int his path hlr > hll while hl = hlr + 1 so [hlr] > 1, so it should be [Node]*)let{l=lrl;v=lrv;r=lrr;_}=~!lrincreate(unsafe_node~l:ll~v:lv~r:lrl)lrv(unsafe_node~l:lrr~v~r)elseifhr>hl+2then(* hr is at least of height > 2 [3], so it should be [Node] *)let{l=rl;v=rv;r=rr;_}=~!rinifheightrr>=heightrlthencreate(unsafe_node~l~v~r:rl)rvrrelse(* In this path hrl > hrr while hr = hrl + 1, so [hrl] > 1, so it should be [Node] *)let{l=rll;v=rlv;r=rlr;_}=~!rlincreate(unsafe_node~l~v~r:rll)rlv(unsafe_node~l:rlr~v:rv~r:rr)elseunsafe_node~l~v~r(* Beware: those two functions assume that the added v is *strictly*
smaller (or bigger) than all the present elements in the tree; it
does not test for equality with the current min (or max) element.
Indeed, they are only used during the "join" operation which
respects this precondition.
*)letrecadd_min_elementx=function|Empty->singletonx|Leafv->unsafe_node~l:(singletonx)~v~r:Empty|Node{l;v;r;_}->bal(add_min_elementxl)vrletrecadd_max_elementx=function|Empty->singletonx|Leafv->unsafe_node~l:Empty~v~r:(singletonx)|Node{l;v;r;_}->ballv(add_max_elementxr)(* Same as create and bal, but no assumptions are made on the
relative heights of l and r. *)letrecjoinlvr=match(l,r)with|(Empty,_)->add_min_elementvr|(_,Empty)->add_max_elementvl|(Leaf_,Leaf_)->unsafe_node~l~v~r|(Leaf_,Node{l=rl;v=rv;r=rr;h=rh})->ifrh>3thenbal(joinlvrl)rvrrelsecreatelvr|(Node{l=ll;v=lv;r=lr;h=lh},Leaf_)->iflh>3thenballllv(joinlrvr)elsecreatelvr|(Node{l=ll;v=lv;r=lr;h=lh},Node{l=rl;v=rv;r=rr;h=rh})->iflh>rh+2thenballllv(joinlrvr)elseifrh>lh+2thenbal(joinlvrl)rvrrelsecreatelvr(* Smallest and greatest element of a set *)letrecmin_elt=function|Empty->raiseNot_found|Leafv->v|Node{l=Empty;v;_}->v|Node{l;_}->min_eltlletrecmin_elt_opt=function|Empty->None|Leafv->Somev|Node{l=Empty;v;_}->Somev|Node{l;_}->min_elt_optlletrecmax_elt=function|Empty->raiseNot_found|Node{v;r=Empty;_}->v|Leafv->v|Node{r;_}->max_eltrletrecmax_elt_opt=function|Empty->None|Node{v;r=Empty;_}->Somev|Leafv->Somev|Node{r;_}->max_elt_optr(* Remove the smallest element of the given set *)letrecremove_min_elt=function|Empty->invalid_arg"Set.remove_min_elt"|Leaf_->Empty|Node{l=Empty;r;_}->r|Node{l;v;r;_}->bal(remove_min_eltl)vr(* Merge two trees l and r into one.
All elements of l must precede the elements of r.
Assume | height l - height r | <= 2. *)letmerget1t2=match(t1,t2)with|(Empty,t)->t|(t,Empty)->t|(_,_)->balt1(min_eltt2)(remove_min_eltt2)(* 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|(_,_)->joint1(min_eltt2)(remove_min_eltt2)letreccardinal=function|Empty->0|Leaf_->1|Node{l;r;_}->cardinall+1+cardinalrletrecelements_auxaccu=function|Empty->accu|Leafv->v::accu|Node{l;v;r;_}->elements_aux(v::elements_auxaccur)lletelementss=elements_aux[]sletempty=Emptylet[@inline]is_empty=function|Empty->true|_->falseletof_sorted_listl=letrecsubnl=match(n,l)with|(0,l)->(Empty,l)|(1,x0::l)->(singletonx0,l)|(2,x0::x1::l)->(Node{l=singletonx0;v=x1;r=Empty;h=2},l)|(3,x0::x1::x2::l)->(Node{l=singletonx0;v=x1;r=singletonx2;h=2},l)|(n,l)->letnl=n/2inlet(left,l)=subnllin(matchlwith|[]->assertfalse|mid::l->let(right,l)=sub(n-nl-1)lin(createleftmidright,l))infst(sub(List.lengthl)l)type'at1='at0=private|Empty|Leafof'a|Nodeof{h:int;v:'a;l:'at0;r:'at0;}moduleMake(Ord:OrderedType):Swithtypeelt=Ord.t=structtypeelt=Ord.ttypet=eltt1letsingleton=singleton(* Insertion of one element *)letmin_elt_opt=min_elt_optletmax_elt_opt=max_elt_optletmin_elt=min_eltletmax_elt=max_eltletelements=elementsletcardinal=cardinalletis_empty=is_emptyletempty=emptyletchoose=min_eltletchoose_opt=min_elt_optletrecaddxt=matchtwith|Empty->singletonx|Leafv->letc=Ord.comparexvinifc=0thentelseifc<0thenunsafe_node~l:(singletonx)~v~r:emptyelseunsafe_node~l:t~v:x~r:empty|Node{l;v;r;_}ast->letc=Ord.comparexvinifc=0thentelseifc<0thenletll=addxlinifl==llthentelseballlvrelseletrr=addxrinifr==rrthentelseballvrrlet(@>)=add(* Splitting. split x s returns a triple (l, present, r) where
- l is the set of elements of s that are < x
- r is the set of elements of s that are > x
- present is false if s contains no element equal to x,
or true if s contains an element equal to x. *)letrecsplitxtree=matchtreewith|Empty->(empty,false,empty)|Leafv->letc=Ord.comparexvinifc=0then(empty,true,empty)elseifc<0then(empty,false,tree)else(tree,false,empty)|Node{l;v;r;_}->letc=Ord.comparexvinifc=0then(l,true,r)elseifc<0thenlet(ll,pres,rl)=splitxlin(ll,pres,joinrlvr)elselet(lr,pres,rr)=splitxrin(joinlvlr,pres,rr)(* Implementation of the set operations *)letrecmemx=function|Empty->false|Leafv->letc=Ord.comparexvinc=0|Node{l;v;r;_}->letc=Ord.comparexvinc=0||memx(ifc<0thenlelser)letrecremovextree=matchtreewith|Empty->empty|Leafv->letc=Ord.comparexvinifc=0thenemptyelsetree|Node{l;v;r;_}ast->letc=Ord.comparexvinifc=0thenmergelrelseifc<0thenletll=removexlinifl==llthentelseballlvrelseletrr=removexrinifr==rrthentelseballvrrletrecunions1s2=match(s1,s2)with|(Empty,t2)->t2|(t1,Empty)->t1|(Leafv,s2)->addvs2|(s1,Leafv)->addvs1|(Node{l=l1;v=v1;r=r1;h=h1},Node{l=l2;v=v2;r=r2;h=h2})->ifh1>=h2thenifh2=1thenaddv2s1elselet(l2,_,r2)=splitv1s2injoin(unionl1l2)v1(unionr1r2)elseifh1=1thenaddv1s2elselet(l1,_,r1)=splitv2s1injoin(unionl1l2)v2(unionr1r2)letrecinters1s2=match(s1,s2)with|(Empty,_)->empty|(_,Empty)->empty|(Leafv,_)->ifmemvs2thens1elseempty|(Node{l=l1;v=v1;r=r1;_},t2)->(matchsplitv1t2with|(l2,false,r2)->concat(interl1l2)(interr1r2)|(l2,true,r2)->join(interl1l2)v1(interr1r2))(* Same as split, but compute the left and right subtrees
only if the pivot element is not in the set. The right subtree
is computed on demand. *)typesplit_bis=|Found|NotFoundoft*(unit->t)letrecsplit_bisx=function|Empty->NotFound(empty,(fun()->empty))|Leafv->letc=Ord.comparexvinifc=0thenFoundelseNotFound(empty,(fun()->empty))|Node{l;v;r;_}->letc=Ord.comparexvinifc=0thenFoundelseifc<0thenmatchsplit_bisxlwith|Found->Found|NotFound(ll,rl)->NotFound(ll,(fun()->join(rl())vr))else(matchsplit_bisxrwith|Found->Found|NotFound(lr,rr)->NotFound(joinlvlr,rr))letrecdisjoints1s2=match(s1,s2)with|(Empty,_)|(_,Empty)->true|(Leafv,s)|(s,Leafv)->not(memvs)|(Node{l=l1;v=v1;r=r1;_},t2)->ifs1==s2thenfalseelse(matchsplit_bisv1t2with|NotFound(l2,r2)->disjointl1l2&&disjointr1(r2())|Found->false)letrecdiffs1s2=match(s1,s2)with|(Empty,_)->empty|(t1,Empty)->t1|(Leafv,_)->ifmemvs2thenemptyelses1|(Node{l=l1;v=v1;r=r1;_},t2)->(matchsplitv1t2with|(l2,false,r2)->join(diffl1l2)v1(diffr1r2)|(l2,true,r2)->concat(diffl1l2)(diffr1r2))letreccompare_auxe1e2=match(e1,e2)with|(End,End)->0|(End,_)->-1|(_,End)->1|(More(v1,r1,e1),More(v2,r2,e2))->letc=Ord.comparev1v2inifc<>0thencelsecompare_aux(cons_enumr1e1)(cons_enumr2e2)letcompares1s2=compare_aux(cons_enums1End)(cons_enums2End)letequals1s2=compares1s2=0letrecsubsets1s2=match(s1,s2)with|(Empty,_)->true|(_,Empty)->false|(Leafv1,Leafv2)->letc=Ord.comparev1v2inifc=0thentrueelsefalse|(Node{v=v1;h;_},Leafv2)->h=1&&(* conservative here *)Ord.comparev1v2=0|(Leafv1,Node{l=l2;v=v2;r=r2;_})->letc=Ord.comparev1v2inifc=0thentrueelseifc<0thensubsets1l2elsesubsets1r2|(Node{l=l1;v=v1;r=r1;_},(Node{l=l2;v=v2;r=r2;_}ast2))->letc=Ord.comparev1v2inifc=0thensubsetl1l2&&subsetr1r2elseifc<0then(* Better to keep invariant here, since our unsafe code relies on such invariant
*)subset(unsafe_node~l:l1~v:v1~r:empty)l2&&subsetr1t2elsesubset(unsafe_node~l:empty~v:v1~r:r1)r2&&subsetl1t2letreciterf=function|Empty->()|Leafv->fv|Node{l;v;r;_}->iterfl;fv;iterfrletrecfoldfsaccu=matchswith|Empty->accu|Leafv->fvaccu|Node{l;v;r;_}->foldfr(fv(foldflaccu))letrecfor_allp=function|Empty->true|Leafv->pv|Node{l;v;r;_}->pv&&for_allpl&&for_allprletrecexistsp=function|Empty->false|Leafv->pv|Node{l;v;r;_}->pv||existspl||existsprletrecfilterptree=matchtreewith|Empty->empty|Leafv->letpv=pvinifpvthentreeelseempty|Node{l;v;r;_}ast->(* call [p] in the expected left-to-right order *)letl'=filterplinletpv=pvinletr'=filterprinifpvthenifl==l'&&r==r'thentelsejoinl'vr'elseconcatl'r'letrecpartitionptree=matchtreewith|Empty->(empty,empty)|Leafv->letpv=pvinifpvthen(tree,empty)else(empty,tree)|Node{l;v;r;_}->(* call [p] in the expected left-to-right order *)let(lt,lf)=partitionplinletpv=pvinlet(rt,rf)=partitionprinifpvthen(joinltvrt,concatlfrf)else(concatltrt,joinlfvrf)letrecfindx=function|Empty->raiseNot_found|Leafv->letc=Ord.comparexvinifc=0thenvelseraiseNot_found|Node{l;v;r;_}->letc=Ord.comparexvinifc=0thenvelsefindx(ifc<0thenlelser)letrecfind_optx=function|Empty->None|Leafv->letc=Ord.comparexvinifc=0thenSomevelseNone|Node{l;v;r;_}->letc=Ord.comparexvinifc=0thenSomevelsefind_optx(ifc<0thenlelser)lettry_joinlvr=(* [join l v r] can only be called when (elements of l < v <
elements of r); use [try_join l v r] when this property may
not hold, but you hope it does hold in the common case *)if(is_emptyl||Ord.compare(max_eltl)v<0)&&(is_emptyr||Ord.comparev(min_eltr)<0)thenjoinlvrelseunionl(addvr)letrecmapftree=matchtreewith|Empty->empty|Leafv->letv'=fvinifv==v'thentreeelsesingletonv'|Node{l;v;r;_}ast->(* enforce left-to-right evaluation order *)letl'=mapflinletv'=fvinletr'=mapfrinifl==l'&&v==v'&&r==r'thentelsetry_joinl'v'r'letof_listl=matchlwith|[]->empty|[x0]->singletonx0|[x0;x1]->x1@>singletonx0|[x0;x1;x2]->x2@>x1@>singletonx0|[x0;x1;x2;x3]->x3@>x2@>x1@>singletonx0|[x0;x1;x2;x3;x4]->x4@>x3@>x2@>x1@>singletonx0|_->of_sorted_list(List.sort_uniqOrd.comparel)letto_seq=to_seqletmake_pppp_keyfmtiset=Format.fprintffmt"@[<2>{";letelements=elementsisetin(matchelementswith|[]->()|_->Format.fprintffmt" ");ignore(List.fold_left(funseps->ifsepthenFormat.fprintffmt";@ ";pp_keyfmts;true)falseelements);(matchelementswith|[]->()|_->Format.fprintffmt" ");Format.fprintffmt"@,}@]"letof_increasing_iterator_unchecked=of_increasing_iterator_uncheckedletof_sorted_array_unchecked=of_sorted_array_uncheckedletrecfind_first_opt_auxv0f=function|Empty->Somev0|Leafv->iffvthenSomevelseSomev0|Node{l;v;r;_}->iffvthenfind_first_opt_auxvflelsefind_first_opt_auxv0frletrecfind_first_optf=function|Empty->None|Leafv->iffvthenSomevelseNone|Node{l;v;r;_}->iffvthenfind_first_opt_auxvflelsefind_first_optfrend