123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237moduletypeS=sigtypekeytype'attype'adiff={(* common : 'a t; *)(* updated : ('a * 'a) t; *)added:'at;removed:'at;}valdiff:old:'at->'at->'adiffvaladd_diff:'adiff->'at->'atvalsub_diff:'adiff->'at->'atvalrange:start:keyoption->end_exc:keyoption->'at->'atendmoduletypeS_bucketed=sigtype'amaptypesettypediff_bucketed={(* common : set map; *)added:setmap;removed:setmap;}valdiff_bucketed:old:setmap->setmap->diff_bucketedvaladd_diff_bucketed:diff_bucketed->setmap->setmapvalsub_diff_bucketed:diff_bucketed->setmap->setmapendmoduleMake(M:Map.S):Swithtypekey:=M.keyandtype'at:='aM.t=structtype'at='aM.ttype'adiff={(* common : 'a t; *)(* updated : ('a * 'a) t; *)added:'at;removed:'at;}(* let get_common (m1 : 'a t) (m2 : 'a t) : 'a t =
* M.merge
* (fun _key x1 x2 ->
* match (x1, x2) with
* | None, None -> None
* | Some _, None -> None
* | None, Some _ -> None
* | Some x1, Some x2 -> if x1 = x2 then Some x1 else None)
* m1 m2 *)(* let get_updated (m1 : 'a t) (m2 : 'a t) : ('a * 'a) t =
* M.merge
* (fun _key x1 x2 ->
* match (x1, x2) with
* | None, None -> None
* | Some _, None -> None
* | None, Some _ -> None
* | Some x1, Some x2 -> if x1 <> x2 then Some (x1, x2) else None)
* m1 m2 *)letget_added(m1:'at)(m2:'at):'at=M.merge(fun_keyx1x2->match(x1,x2)with|None,_->x2|Some_,None->None|Somex1,Somex2->ifx1=x2thenNoneelseSomex2)m1m2letget_removed(m1:'at)(m2:'at):'at=M.merge(fun_keyx1x2->match(x1,x2)with|None,_->None|Some_,None->x1|Somex1,Somex2->ifx1=x2thenNoneelseSomex1)m1m2letdiff~(old:'at)(m:'at):'adiff={(* common = get_common old m; *)(* updated = get_updated old m; *)added=get_addedoldm;removed=get_removedoldm;}letadd_diff(diff:'adiff)(m:'at):'at=m(* apply updates *)(* |> M.mapi (fun key x ->
* match M.find_opt key diff.updated with
* | None -> x
* | Some (x1, x2) -> if x1 = x then x2 else raise Exceptions.Invalid_diff) *)(* remove *)|>M.merge(fun_keyto_be_removedx->match(to_be_removed,x)with|None,_->x|_,None->raiseExceptions.Invalid_diff|Someto_be_removed,Somex->ifx=to_be_removedthenNoneelseraiseExceptions.Invalid_diff)diff.removed(* add *)|>M.union(fun_keyadded_->Someadded)diff.addedletsub_diff(diff:'adiff)(m:'at):'at=m(* revert updates *)(* |> M.mapi (fun key x ->
* match M.find_opt key diff.updated with
* | None -> x
* | Some (x1, x2) -> if x2 = x then x1 else raise Exceptions.Invalid_diff) *)(* revert add *)|>M.merge(fun_keyto_be_removedx->match(to_be_removed,x)with|None,_|_,None->x|Someto_be_removed,Somex->ifx=to_be_removedthenNoneelseraiseExceptions.Invalid_diff)diff.added(* revert remove *)|>M.union(fun_keyremoved_->Someremoved)diff.removedletrange~(start:M.keyoption)~(end_exc:M.keyoption)(m:'at):'at=letadd'(key:M.key)(x:'aoption)(m:'at)=matchxwithNone->m|Somex->M.addkeyxminmatch(start,end_exc)with|None,None->m|Somestart,None->let_,eq,after=M.splitstartminadd'starteqafter|None,Someend_exc->letbefore,eq,_=M.splitend_excminadd'end_exceqbefore|Somestart,Someend_exc->letafter_or_from_start=let_,eq,after=M.splitstartminadd'starteqafterinletbefore_or_on_end_exc=letbefore,eq,_=M.splitend_excafter_or_from_startinadd'end_exceqbeforeinbefore_or_on_end_excendmoduleMake_bucketed(Map:Map.S)(Set:Set.S):S_bucketedwithtype'amap:='aMap.tandtypeset:=Set.t=structtype'amap='aMap.ttypeset=Set.ttypediff_bucketed={(* common : set map; *)added:setmap;removed:setmap;}(* let get_common (m1 : set map) (m2 : set map) : set map =
* Map.merge
* (fun _key s1 s2 ->
* match (s1, s2) with
* | None, None -> None
* | Some _, None -> None
* | None, Some _ -> None
* | Some s1, Some s2 -> Some (Set.inter s1 s2))
* m1 m2 *)letget_added(m1:setmap)(m2:setmap):setmap=Map.merge(fun_keys1s2->match(s1,s2)with|None,_->s2|Some_,None->None|Somes1,Somes2->ifSet.equals1s2thenNoneelseSome(Set.diffs2s1))m1m2letget_removed(m1:setmap)(m2:setmap):setmap=Map.merge(fun_keys1s2->match(s1,s2)with|None,_->None|Some_,None->s1|Somes1,Somes2->ifSet.equals1s2thenNoneelseSome(Set.diffs1s2))m1m2letdiff_bucketed~(old:setmap)(m:setmap):diff_bucketed={(* common = get_common old m; *)added=get_addedoldm;removed=get_removedoldm;}letadd_diff_bucketed(diff:diff_bucketed)(m:setmap):setmap=m(* remove *)|>Map.merge(fun_keyto_be_removeds->match(to_be_removed,s)with|None,_->s|_,None->raiseExceptions.Invalid_diff|Someto_be_removed,Somes->ifSet.equalto_be_removedsthenNoneelseSome(Set.diffsto_be_removed))diff.removed(* add *)|>Map.union(fun_keys1s2->Some(Set.unions1s2))diff.addedletsub_diff_bucketed(diff:diff_bucketed)(m:setmap):setmap=m(* revert add *)|>Map.merge(fun_keyto_be_removeds->match(to_be_removed,s)with|None,_->s|_,None->raiseExceptions.Invalid_diff|Someto_be_removed,Somes->ifSet.equalto_be_removedsthenNoneelseSome(Set.diffsto_be_removed))diff.added(* revert remove *)|>Map.union(fun_keys1s2->Some(Set.unions1s2))diff.removedend