123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128moduletypeMEASURE=sigtype+'ameasurabletypemeasurevalempty:measurevalcat:measure->'ameasurable->measure->measureendmoduleMake(M:MEASURE)=structtype'at=|Leaf|Nodeofint*'at*'aM.measurable*'at*M.measureletsize=function|Node(s,_,_,_,_)->s|Leaf->0letmeasure=function|Node(_,_,_,_,m)->m|Leaf->M.empty(** {1 Balance criteria}
Functions are not symmetric.
The first argument should always be of the same power of two or smaller
(guaranteed by construction). *)(** [smaller_ell smin smax] iff
- [smin] is less than [smax]
- [smin] and [smax] differs by less than two magnitude orders, i.e
msbs(smin) >= msbs(smax) - 1
where msbs is the index of the most significant bit set *)letsmaller_ellsminsmax=(smin<smax)&&((sminlandsmax)lsl1<smax)(** [disbalanced smin smax] check if two sub-trees of size [smin] and [smax],
are disbalanced. That is, msbs(smin) < msbs(smax) - 1 *)letdisbalancedsminsmax=smaller_ellsmin(smaxlsr1)(** {1 Smart but not too much constructors} *)(** Construct node and check balance
let node_ l x r =
let sl = size l and sr = size r in
if sl < sr then
assert (not (disbalanced sl sr))
else
assert (not (disbalanced sr sl));
let ml = measure l and mr = measure r in
Node (sl + 1 + sr, l, x, r, M.cat ml x mr)
*)(** Construct Node *)letnode_lxr=Node(sizel+1+sizer,l,x,r,M.cat(measurel)x(measurer))(** Rotations *)letrot_leftlxrk=matchrwith|Node(_,rl,y,rr,_)->k(klxrl)yrr|_->assertfalseletrot_rightlyrk=matchlwith|Node(_,ll,x,lr,_)->kllx(klryr)|_->assertfalse(** Balancing *)letinc_leftlxrk=letr=matchrwith|Node(_,rl,y,rr,_)whensmaller_ell(sizerr)(sizerl)->rot_rightrlyrrk|_->rinrot_leftlxrkletinc_rightlyrk=letl=matchlwith|Node(_,ll,x,lr,_)whensmaller_ell(sizell)(sizelr)->rot_leftllxlrk|_->linrot_rightlyrk(** Balance trees leaning to the right *)letrecnode_leftlxr=ifdisbalanced(sizel)(sizer)theninc_leftlxrnode_leftelsenode_lxr(** Balance trees leaning to the left *)letrecnode_rightlyr=ifdisbalanced(sizer)(sizel)theninc_rightlyrnode_rightelsenode_lyr(** Public interface *)letleaf=Leafletnodelxr=matchl,rwith|Leaf,Leaf->node_leafxleaf|l,rwhensizel<sizer->node_leftlxr|l,r->node_rightlxrletrecjoinlr=matchl,rwith|Leaf,t|t,Leaf->t|Node(sl,ll,x,lr,_),Node(sr,rl,y,rr,_)->ifsl<=srthennode(joinlrl)yrrelsenodellx(joinlrr)letrecrankn=function|Leaf->raiseNot_found|Node(_,l,x,r,_)->letsl=sizelinifn=slthenxelseifn<slthenranknlelserank(n-1-sl)rend