123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298(******************************************************************************)(* *)(* Menhir *)(* *)(* Copyright Inria. All rights reserved. This file is distributed under *)(* the terms of the GNU Library General Public License version 2, with a *)(* special exception on linking, as described in the file LICENSE. *)(* *)(******************************************************************************)(* This is a stripped-down copy of the weight-balanced binary trees found in
the library Baby by François Pottier. *)type'vtree=|TLeaf|TNodeof{l:'vtree;v:'v;r:'vtree;w:int}let[@inline]weightt=matchtwith|TLeaf->1|TNode{w;_}->wlet[@inline]cardinalt=weightt-1letalpha=29(* in percent *)let[@inline]not_left_heavywlwr=alpha*wl<=(100-alpha)*wrlet[@inline]left_heavywlwr=not(not_left_heavywlwr)let[@inline]not_right_heavywlwr=not_left_heavywrwllet[@inline]right_heavywlwr=not(not_right_heavywlwr)let[@inline]like_weightswlwr=not_left_heavywlwr&¬_right_heavywlwrlet[@inline]siblingslr=like_weights(weightl)(weightr)letreccheckt=matchtwith|TLeaf->()|TNode{l;r;w;_}->checkl;checkr;assert(w=weightl+weightr);assert(siblingslr)let[@inline]create''wlvr=assert(w=weightl+weightr);(* This assertion can fail, (hopefully) just because a double rotation
can temporarily create a node that does not satisfy the invariant.
assert (siblings l r);
*)TNode{l;v;r;w}let[@inline]createlvr=letw=weightl+weightrincreate''wlvrlet[@inline]create'wllvwrr=assert(wl=weightl&&wr=weightr);letw=wl+wrincreate''wlvrlet[@inline]singletonx=letw=2increate''wTLeafxTLeafletimpossible()=assertfalseletrotate_leftlvr=matchrwith|TLeaf->impossible()|TNode{l=rl;v=rv;r=rr;_}->create(createlvrl)rvrrletrotate_rightlvr=matchlwith|TLeaf->impossible()|TNode{l=ll;v=lv;r=lr;_}->createlllv(createlrvr)letbalance_right_heavywllvwrr=assert(wl=weightl&&wr=weightr);assert(right_heavywlwr);matchrwith|TLeaf->impossible()|TNode{l=rl;v=rv;r=rr;_}->letwrl=weightrlinletwrr=wr-wrlinassert(wrr=weightrr);iflike_weightswlwrl&&like_weights(wl+wrl)wrrthen(* [rotate_left l v r] *)letw=wl+wrincreate''w(create'wllvwrlrl)rvrrelserotate_leftlv(rotate_rightrlrvrr)letbalance_left_heavywllvwrr=assert(wl=weightl&&wr=weightr);assert(left_heavywlwr);matchlwith|TLeaf->impossible()|TNode{l=ll;v=lv;r=lr;_}->letwll=weightllinletwlr=wl-wllinassert(wlr=weightlr);iflike_weightswlrwr&&like_weightswll(wlr+wr)then(* [rotate_right l v r] *)letw=wl+wrincreate''wlllv(create'wlrlrvwrr)elserotate_right(rotate_leftlllvlr)vr(* The following functions are unused.
let[@inline] balance_maybe_right_heavy wl l v wr r =
assert (wl = weight l && wr = weight r);
assert (not_left_heavy wl wr);
if not_right_heavy wl wr then
create' wl l v wr r
else
balance_right_heavy wl l v wr r
let[@inline] balance_maybe_left_heavy wl l v wr r =
assert (wl = weight l && wr = weight r);
assert (not_right_heavy wl wr);
if not_left_heavy wl wr then
create' wl l v wr r
else
balance_left_heavy wl l v wr r
let rec join_maybe_left_heavy l v wr r =
assert (wr = weight r);
let wl = weight l in
assert (not_right_heavy wl wr);
if not_left_heavy wl wr then
create' wl l v wr r
else
join_left_heavy wl l v wr r
and join_left_heavy wl l v wr r =
assert (wl = weight l && wr = weight r);
assert (left_heavy wl wr);
match l with
| TLeaf -> impossible()
| TNode { l = ll; v = lv; r = lr; _ } ->
let wll = weight ll in
let wlr = wl - wll in
assert (wlr = weight lr);
balance_maybe_right_heavy
wll ll
lv
(wlr + wr) (join_maybe_left_heavy lr v wr r)
let rec join_maybe_right_heavy wl l v r =
assert (wl = weight l);
let wr = weight r in
assert (not_left_heavy wl wr);
if not_right_heavy wl wr then
create' wl l v wr r
else
join_right_heavy wl l v wr r
and join_right_heavy wl l v wr r =
assert (wl = weight l && wr = weight r);
assert (right_heavy wl wr);
match r with
| TLeaf -> impossible()
| TNode { l = rl; v = rv; r = rr; _ } ->
let wrl = weight rl in
let wrr = wr - wrl in
assert (wrr = weight rr);
balance_maybe_left_heavy
(wl + wrl) (join_maybe_right_heavy wl l v rl)
rv
wrr rr
let join l v r =
let wl = weight l and wr = weight r in
if not_left_heavy wl wr then
if not_right_heavy wl wr then
create' wl l v wr r
else
join_right_heavy wl l v wr r
else
join_left_heavy wl l v wr r
*)letrecquasi_siblingslr=ifweightl<=weightrthenlike_weights(weightl)(weightr-1)||like_weights(weightl+1)(weightr)elsequasi_siblingsrlletjoin_quasi_siblingslvr=assert(quasi_siblingslr);letwl=weightlandwr=weightrinifnot_left_heavywlwrthenifnot_right_heavywlwrthencreate'wllvwrrelsebalance_right_heavywllvwrrelsebalance_left_heavywllvwrrletempty=TLeafletrecaddcmpxt=matchtwith|TLeaf->singletonx|TNode{l;v;r;_}->letc=cmpxvinifc=0thentelseifc<0thenletl'=addcmpxlinifl==l'thentelsejoin_quasi_siblingsl'vrelseletr'=addcmpxrinifr==r'thentelsejoin_quasi_siblingslvr'letrecadd_absentcmpxt=matchtwith|TLeaf->singletonx|TNode{l;v;r;_}->letc=cmpxvinassert(c<>0);ifc<0thenletl'=add_absentcmpxlinifl==l'thentelsejoin_quasi_siblingsl'vrelseletr'=add_absentcmpxrinifr==r'thentelsejoin_quasi_siblingslvr'letrecmemcmpxt=matchtwith|TLeaf->false|TNode{l;v;r;_}->letc=cmpxvinc=0||memcmpx(ifc<0thenlelser)letrecfindcmpxt=matchtwith|TLeaf->None|TNode{l;v;r;_}->letc=cmpxvinifc=0thenSomevelsefindcmpx(ifc<0thenlelser)letreciterft=matchtwith|TLeaf->()|TNode{l;v;r;_}->iterfl;fv;iterfrletrecfor_allpt=matchtwith|TLeaf->true|TNode{l;v;r;_}->for_allpl&&pv&&for_allprlet[@inline]is_singletont=matchtwith|TLeaf->false|TNode{w;_}->(* [w] is [weight t]. The weight of a singleton is 2. Relying on the
weight removes the need to read the fields [l] and [r]. *)w=2let[@inline]extract_singletont=matchtwith|TNode{l;v;r;w}->assert(l=TLeaf&&r=TLeaf&&w=2);v|_->assertfalse