123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104(*
* Uref -- unifiable references
* Copyright (C) 2011 Batteries Included Development Team
*
* This library is free software; 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; either
* version 2.1 of the License, or (at your option) any later version,
* with the special exception on linking described in file LICENSE.
*
* This library 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)(* Implements union-find with ranks and path-compression *)type'auref_contents=|Rankedof'a*int|Ptrof'aurefand 'auref='auref_contents reftype'at='aurefletrecfindur=match!urwith|Ptrp->letvr=findpinur:= Ptrvr;vr|Ranked_->urleturefx=ref(Ranked (x,0))letugetur=match!(findur)with|Ptr_->assert false|Ranked(x,_)->xletuseturx=letur=find urinmatch!urwith|Ptr_->assertfalse|Ranked(_,r)->ur:=Ranked(x,r)letequal urvr=findur==findvrletunite?selurvr =(* we use ?sel instead of ?(sel=(fun x _y -> x)) because we want to be
able to know whether a selection function was passed, for
optimization purposes: when sel is the default (expected common
case), we can take a short path in the (ur == vr) case. *)letur=findurinletvr =findvr inifur==vrthenbeginmatchselwith|None->()|Somesel->(* even when ur and vr are the same reference, we need to apply
the selection function, as [sel x x] may be different from [x].
For example, [unite ~sel:(fun _ _ -> v) r r] would fail
to set the content of [r] to [v] otherwise. *)match!urwith|Ptr_-> assertfalse|Ranked(x,r)->letx'=selxxinur:=Ranked(x',r)endelsematch!ur,!vrwith|_,Ptr_|Ptr_,_->assertfalse|Ranked(x,xr),Ranked(y,yr)->letz=matchselwith|None->x(* in the default case, pick x *)|Somesel->selxyinifxr=yrthenbeginur :=Ranked(z,xr+1);vr:=Ptrurendelseifxr<yrthenbeginur :=Ranked(z,xr);vr:=Ptrurendelsebeginvr:=Ranked(z,yr);ur:=Ptrvrendletprinteleproutur=match !(find ur)with|Ptr_->assert false|Ranked(x,_)->BatInnerIO.nwriteout"uref ";elepr outx(*$T print let u1 = uref 2 and u2 = uref 3 in unite ~sel:(+) u1 u2; \
BatIO.to_string (print BatInt.print) u1 = "uref 5" && \
BatIO.to_string (print BatInt.print) u2 = "uref 5"
*)