123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737(* ReactiveData
* https://github.com/hhugo/reactiveData
* Copyright (C) 2014 Hugo Heuzard
*
* This program 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, with linking exception;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program 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 program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)moduletypeDATA=sigtype'adatatype'apatchvalmerge:'apatch->'adata->'adatavalmap_patch:('a->'b)->'apatch->'bpatchvalmap_data:('a->'b)->'adata->'bdatavalempty:'adatavalequal:('a->'a->bool)->'adata->'adata->boolvaldiff:eq:('a->'a->bool)->'adata->'adata->'apatchendmoduletypeS=sigtype'attype'adatatype'apatchtype'amsg=Patchof'apatch|Setof'adatatype'ahandlevalempty:'atvalcreate:'adata->'at*'ahandlevalfrom_event:'adata->'amsgReact.E.t->'atvalfrom_signal:?eq:('a->'a->bool)->'adataReact.S.t->'atvalconst:'adata->'atvalpatch:'ahandle->'apatch->unitvalset:'ahandle->'adata->unitvalmap_msg:('a->'b)->'amsg->'bmsgvalmap:('a->'b)->'at->'btvalvalue:'at->'adatavalfold:('a->'bmsg->'a)->'bt->'a->'aReact.signalvalsignal:?eq:('a->'a->bool)->'at->'adataReact.S.tvalevent:'at->'amsgReact.E.tendmoduleMake(D:DATA):Swithtype'adata='aD.dataandtype'apatch='aD.patch=structtype'adata='aD.datatype'apatch='aD.patchletmerge=D.mergeletmap_patch=D.map_patchletmap_data=D.map_datatype'amsg=Patchof'apatch|Setof'adatatype'ahandle=?step:React.step->'amsg->unittype'amut={current:'adataref;event:'amsgReact.E.t}type'at=Constof'adata|Mutof'amutletempty=ConstD.emptyletcreatel=letinitial_event,send=React.E.create()inletcurrent=reflinletevent=React.E.map(funmsg->(matchmsgwith|Setl->current:=l|Patchp->current:=mergep!current);msg)initial_eventin(Mut{current;event},send)letfrom_eventlinitial_event=letcurrent=reflinletevent=React.E.map(funmsg->(matchmsgwith|Setl->current:=l|Patchp->current:=mergep!current);msg)initial_eventinMut{current;event}letconstx=Constxletmap_msg(f:'a->'b):'amsg->'bmsg=function|Setl->Set(map_datafl)|Patchp->Patch(map_patchfp)letmapfs=matchswith|Constx->Const(map_datafx)|Muts->letcurrent=ref(map_dataf!(s.current))inletevent=React.E.map(funmsg->letmsg=map_msgfmsgin(matchmsgwith|Setl->current:=l|Patchp->current:=mergep!current);msg)s.eventinMut{current;event}letvalues=matchswithConstc->c|Muts->!(s.current)letevents=matchswithConst_->React.E.never|Muts->s.eventletpatch(s:'ahandle)p=s(Patchp)letset(s:'ahandle)p=s(Setp)letfoldfsacc=matchswith|Constc->React.S.const(facc(Setc))|Muts->letacc=facc(Set!(s.current))inReact.S.foldfaccs.eventletsignal?(eq=(=))(s:'at):'adataReact.S.t=matchswith|Constc->React.S.constc|Muts->React.S.fold~eq:(D.equaleq)(funlmsg->matchmsgwithSetl->l|Patchp->mergepl)!(s.current)s.eventletfrom_signal?(eq=(=))s=letfd'd=Patch(D.diff~eqdd')infrom_event(React.S.values)(React.S.difffs)endmoduleDataList=structtype'adata='alisttype'ap=Iofint*'a|Rofint|Uofint*'a|Xofint*inttype'apatch='aplistletempty=[]letmap_data=List.mapletmap_patchf=function|I(i,x)->I(i,fx)|Ri->Ri|X(i,j)->X(i,j)|U(i,x)->U(i,fx)letmap_patchf=List.map(map_patchf)letmerge_popl=matchopwith|I(i',x)->leti=ifi'<0thenList.lengthl+1+i'elsei'inletrecauxaccnl=match(n,l)with|0,l->List.rev_appendacc(x::l)|_,[]->failwith"ReactiveData.Rlist.merge"|n,x::xs->aux(x::acc)(predn)xsinaux[]il|Ri'->leti=ifi'<0thenList.lengthl+i'elsei'inletrecauxaccnl=match(n,l)with|0,_::l->List.rev_appendaccl|_,[]->failwith"ReactiveData.Rlist.merge"|n,x::xs->aux(x::acc)(predn)xsinaux[]il|U(i',x)->leti=ifi'<0thenList.lengthl+i'elsei'inleta=Array.of_listlina.(i)<-x;Array.to_lista|X(i',offset)->leta=Array.of_listlinletlen=Array.lengthainleti=ifi'<0thenlen+i'elsei'inletv=a.(i)inifoffset>0then(ifi+offset>=lenthenfailwith"ReactiveData.Rlist.merge";forj=itoi+offset-1doa.(j)<-a.(j+1)done;a.(i+offset)<-v)else(ifi+offset<0thenfailwith"ReactiveData.Rlist.merge";forj=idowntoi+offset+1doa.(j)<-a.(j-1)done;a.(i+offset)<-v);Array.to_lista(* accumulates into acc i unmodified elements from l *)letreclinear_merge_fwd~accil=assert(i>=0);ifi>0thenmatchlwith|h::l->letacc=h::accinlinear_merge_fwd~acc(i-1)l|[]->invalid_arg"invalid index"else(l,acc)letreclinear_merge~acci0pl=letl,acc=matchpwith|(I(i,_)|Ri|U(i,_))::_wheni>i0->linear_merge_fwd~acc(i-i0)l|_->(l,acc)inmatch(p,l)with|I(i,x)::p,_->linear_merge~accip(x::l)|Ri::p,_::l->linear_merge~accipl|R_::_,[]->invalid_arg"merge: invalid index"|U(i,x)::p,_::l->linear_merge~accip(x::l)|U(_,_)::_,[]->invalid_arg"merge: invalid index"|[],l->List.rev_appendaccl|X(_,_)::_,_->failwith"linear_merge: X not supported"letreclinear_mergeable~np=assert(n>=0);matchpwith|(I(i,_)|Ri|U(i,_))::pwheni>=n->(* negative i's ruled out (among others) *)linear_mergeable~n:ip|_::_->false|[]->trueletmergepl=iflinear_mergeable~n:0pthenlinear_merge~acc:[]0plelseList.fold_left(funlx->merge_pxl)lpletrecequalfl1l2=match(l1,l2)with|x1::l1,x2::l2whenfx1x2->equalfl1l2|[],[]->true|_::_,_::_|_::_,[]|[],_::_->falseletmem(typeu)l=letmoduleH=Hashtbl.Make(structtypet=ulethash=Hashtbl.hashletequal=(==)end)inleth=H.create16inList.iter(funx->H.addhx())l;H.memhletfold_diff?(eq=(=))~acc~remove~addlxly=letmemx=memlxandmemy=memlyinletrecf~acc~leftlxlyn=match(lx,ly)with(* trailing elements to be removed *)|_::lx,[]->letacc=removeaccninf~acc~leftlx[]n(* trailing elements to be added *)|[],y::ly->letacc=addaccnyinf~acc~left[]ly(n+1)(* done! *)|[],[]->acc(* same *)|x::lx,y::lywheneqxy->f~acc~leftlxly(n+1)(* x needs to be removed for sure *)|x::lx,_::_whennot(memyx)->letacc=removeaccninf~acc~leftlxlyn(* y needs to be added for sure *)|_::_,y::lywhennot(memxy)->letacc=addaccnyinf~acc~leftlxly(n+1)(* no more certainty, ~left decides what to recur on *)|_::lx,_::_whenleft->letacc=removeaccninf~acc~left:falselxlyn|_::_,y::ly->letacc=addaccnyinf~acc~left:truelxly(n+1)inf~acc~left:truelxly0letreclist_rev?(acc=[])=function|h::t->letacc=h::accinlist_rev~acct|[]->accletdiff~eqxy=letaddacciv=I(i,v)::accandremoveacci=Ri::accandacc=[]inlist_rev(fold_diff~eq~acc~add~removexy)endmoduleRList=structincludeMake(DataList)moduleD=DataListtype'ap='aD.p=|Iofint*'a|Rofint|Uofint*'a|Xofint*intletconsxs=patchs[D.I(0,x)]letsnocxs=patchs[D.I(-1,x)]letinsertxis=patchs[D.I(i,x)]letupdatexis=patchs[D.U(i,x)]letmoveijs=patchs[D.X(i,j)]letremoveis=patchs[D.Ri]letindex?(eq=(=))lx=letrecfn=function|hd::_wheneqhdx->n|_::tl->f(n+1)tl|[]->raiseNot_foundinf0lletupdate_eq?eq(data,handle)xy=leti=index?eq(valuedata)xinupdateyihandleletremove_last(data,handle)=remove(List.length(valuedata)-1)handleletremove_eq?eq(data,handle)x=leti=index?eq(valuedata)xinremoveihandleletsingletonx=const[x]letsingleton_ss=letfirst=reftrueinlete,send=React.E.create()inletresult=from_event[]einlet(`R_)=lets'=React.S.map(funx->if!firstthen(first:=false;send(Patch[I(0,x)]))elsesend(Patch[U(0,x)]))sinReact.E.retaine(fun()->ignore(React.S.values'))inresultletconcat:'at->'at->'at=funxy->letv1=valuexandv2=valueyinletsize1=ref0andsize2=ref0inletsize_with_patchsizex:'aD.p->unit=function|D.I_->incrsizex|D.R_->decrsizex|D.X_|D.U_->()inletsize_with_setsizexl=sizex:=List.lengthlinsize_with_setsize1v1;size_with_setsize2v2;letupdate_patch1=List.map(funp->letm=matchpwith|D.I(pos,x)->leti=ifpos<0thenpos-!size2elseposinD.I(i,x)|D.Rpos->D.R(ifpos<0thenpos-!size2elsepos)|D.U(pos,x)->D.U((ifpos<0thenpos-!size2elsepos),x)|D.X(i,j)->D.X((ifi<0theni-!size2elsei),j)insize_with_patchsize1m;m)inletupdate_patch2=List.map(funp->letm=matchpwith|D.I(pos,x)->D.I((ifpos<0thenposelse!size1+pos),x)|D.Rpos->D.R(ifpos<0thenposelse!size1+pos)|D.U(pos,x)->D.U((ifpos<0thenposelse!size1+pos),x)|D.X(i,j)->D.X((ifi<0thenielse!size1+i),j)insize_with_patchsize2m;m)inlettuple_ev=React.E.merge(funaccx->match(acc,x)with|(None,p2),`E1x->(Somex,p2)|(p1,None),`E2x->(p1,Somex)|_->assertfalse)(None,None)[React.E.map(fune->`E1e)(eventx);React.E.map(fune->`E2e)(eventy);]inletmerged_ev=React.E.map(funp->matchpwith|Some(Setp1),Some(Setp2)->size_with_setsize1p1;size_with_setsize2p2;Set(p1@p2)|Some(Setp1),None->size_with_setsize1p1;Set(p1@valuey)|None,Some(Setp2)->size_with_setsize2p2;Set(valuex@p2)|Some(Patchp1),Some(Patchp2)->letp1=update_patch1p1inletp2=update_patch2p2inPatch(p1@p2)|Some(Patchp1),None->Patch(update_patch1p1)|None,Some(Patchp2)->Patch(update_patch2p2)|Some(Patch_),Some(Sets2)->lets1=valuexinsize_with_setsize1s1;size_with_setsize2s2;Set(s1@s2)|Some(Sets1),Some(Patch_)->size_with_setsize1s1;lets2=valueyinsize_with_setsize2s2;Set(s1@s2)|None,None->assertfalse)tuple_evinfrom_event(v1@v2)merged_evletinverse:'a.'ap->'ap=function|I(i,x)->I(-i-1,x)|U(i,x)->U(-i-1,x)|Ri->R(-i-1)|X(i,j)->X(-i-1,-j)letrevt=lete=React.E.map(function|Setl->Set(List.revl)|Patchp->Patch(List.mapinversep))(eventt)infrom_event(List.rev(valuet))eletfilterpredl=letmoduleIntMap=Map.Make(Int)inletindex=refIntMap.emptyinletsize=ref0inletfilter_listl=letrecaux(l:'alist)restheir_imy_i=matchlwith|[]->res|x::xs->ifpredxthen(index:=IntMap.addtheir_i(my_i+1)!index;auxxs(x::res)(their_i+1)(my_i+1))elseauxxsres(their_i+1)my_iinsize:=List.lengthl;index:=IntMap.empty;List.rev(auxl[]0(-1))inletnormalisei=ifi<0then!size+1+ielseiinletupdate_index_insertinsert_pos_full_listvisible=letinsert_pos_full_list=normaliseinsert_pos_full_listinletleft_alone,displaced,updatables=IntMap.splitinsert_pos_full_list!indexinletupdatables=matchdisplacedwith|None->updatables|Somedisplaced_in_filtered->IntMap.addinsert_pos_full_listdisplaced_in_filteredupdatablesinletupdate_jj_full_listj_filtered_list=letnew_j_filtered=ifvisiblethenj_filtered_list+1elsej_filtered_listinindex:=IntMap.add(j_full_list+1)new_j_filtered!indexinlet()=IntMap.iterupdate_jupdatablesinletinsert_pos_filtered=ifIntMap.is_emptyleft_alonethen0elsesnd(IntMap.max_bindingleft_alone)+1inifvisiblethenindex:=IntMap.addinsert_pos_full_listinsert_pos_filtered!index;incrsize;insert_pos_filteredinletupdate_index_removeremove_pos_full_list=letwas_visible=IntMap.memremove_pos_full_list!indexinlet_,_,updatables=IntMap.splitremove_pos_full_list!indexinletupdate_jj_full_listj_filtered_list=letnew_j=ifwas_visiblethenj_filtered_listelsej_filtered_list-1inindex:=IntMap.add(j_full_list-1)new_j!indexinifnot(IntMap.is_empty!index)thenletlast_i,_=IntMap.max_binding!indexinindex:=IntMap.removelast_i!indexelse();decrsize;IntMap.iterupdate_jupdatablesinletupdate_index_update_deleteupdate_pos_full_list=let_,_,updatables=IntMap.splitupdate_pos_full_list!indexinletupdate_jj_full_listj_filtered_list=index:=IntMap.addj_full_list(j_filtered_list-1)!indexinindex:=IntMap.removeupdate_pos_full_list!index;IntMap.iterupdate_jupdatablesinletupdate_index_update_insertupdate_pos_full_list=letleft_alone,none,updatables=IntMap.splitupdate_pos_full_list!indexinassert(none=None);letupdate_jj_full_listj_filtered_list=index:=IntMap.addj_full_list(j_filtered_list+1)!indexinletnew_pos_filtered_list=letprevious_pos_filtered=trysnd(IntMap.max_bindingleft_alone)withNot_found->-1inprevious_pos_filtered+1inindex:=IntMap.addupdate_pos_full_listnew_pos_filtered_list!index;IntMap.iterupdate_jupdatables;new_pos_filtered_listinletupdate_index_movefrom_full_listto_full_listto_filtered=letwas_visible=matchto_filteredwithSome_->true|None->falseinletforward=from_full_list<to_full_listinifforwardthenfori_full=from_full_list+1toto_full_listdoletdelta=ifwas_visiblethen-1else0intryleti_filtered=IntMap.findi_full!indexinletnew_val=i_filtered+deltainindex:=IntMap.add(i_full-1)new_val!indexwithNot_found->()doneelsefori_full=from_full_list-1downtoto_full_listdotryletdelta=ifwas_visiblethen1else0inleti_filtered=IntMap.findi_full!indexinletnew_val=i_filtered+deltainindex:=IntMap.add(i_full+1)new_val!indexwithNot_found->()done;matchto_filteredwith|Someto_filtered->index:=IntMap.addto_full_listto_filtered!index|None->index:=IntMap.removeto_full_list!indexinletconvert_p=function|I(i,x)->ifpredxthenletmy_i=update_index_insertitruein[I(my_i,x)]else(ignore(update_index_insertifalse);[])|Ri->leti=normaliseiinletret=tryletj=IntMap.findi!indexin[Rj]withNot_found->[]inlet()=update_index_removeiinret|U(i,x)->(leti=normaliseiintryletold_j=IntMap.findi!indexinifpredxthen[U(old_j,x)]else(update_index_update_deletei;[Rold_j])withNot_found->ifpredxthenletnew_j=update_index_update_insertiin[I(new_j,x)]else[])|X(origin_full,offset_full)->(letorigin_full=normaliseorigin_fullinletdest_full=origin_full+offset_fullintryletorigin_filtered=IntMap.findorigin_full!indexinletdest_filtered=tryIntMap.finddest_full!indexwithNot_found->letsmall_ones,_,_=IntMap.splitorigin_full!indexinifIntMap.is_emptysmall_onesthen0elsesnd(IntMap.max_bindingsmall_ones)+1inupdate_index_moveorigin_fulldest_full(Somedest_filtered);ifdest_filtered!=origin_filteredthen[X(origin_filtered,dest_filtered-origin_filtered)]else[]withNot_found->(* moving an element that was filtered out *)update_index_moveorigin_fulldest_fullNone;[])inletfilter_e=function|Setl->Set(filter_listl)|Patchp->Patch(List.concat(List.mapconvert_pp))inlete=React.E.mapfilter_e(eventl)infrom_event(filter_list(valuel))emoduleIntSet=Set.Make(Int)letfor_allfndata=letmaybe_updateacciv=iffnvthenaccelseIntSet.addiaccinletinit=letrecfoldiacc=function|v::tl->fold(i+1)(maybe_updateacciv)tl|[]->accinfold0IntSet.emptyinletupdate_idx_afterifacc=IntSet.map(funi'->ifi'>=ithenfi'1elsei')accinletf=funacc->function|Setx->initx|Patchupdates->List.fold_left(funacc->function|X(i,i')->ifIntSet.memiacc=IntSet.memi'accthenaccelseifIntSet.memiaccthenIntSet.addi'(IntSet.removeiacc)elseIntSet.addi(IntSet.removei'acc)|Ri->update_idx_afteri(-)(IntSet.removeiacc)|I(i,v)->letacc=update_idx_afteri(+)accinmaybe_updateacciv|U(i,v)->maybe_update(IntSet.removeiacc)iv)accupdatesinReact.S.foldf(init(valuedata))(eventdata)|>React.S.mapIntSet.is_emptyendmoduleRMap(M:Map.S)=structmoduleData=structtype'adata='aM.ttype'ap=[`AddofM.key*'a|`DelofM.key]type'apatch='aplistletmerge_pps=matchpwith`Add(k,a)->M.addkas|`Delk->M.removeksletmergepacc=List.fold_left(funaccp->merge_ppacc)accpletmap_pf=function`Add(k,a)->`Add(k,fa)|`Delk->`Delkletmap_patchf=List.map(map_pf)letmap_datafd=M.mapfdletempty=M.emptyletequalf=M.equalfletdiff~eqxy=letm=letg_keyvw=match(v,w)with|Somev,Somewwheneqvw->None|Some_,Somew->Some(`Uw)|Some_,None->Some`D|None,Somev->Some(`Av)|None,None->NoneinM.mergegxyandgkeyxacc=matchxwith|`Uv->`Delkey::`Add(key,v)::acc|`D->`Delkey::acc|`Av->`Add(key,v)::accandacc=[]inList.rev(M.foldgmacc)endincludeMake(Data)letfilterpredm=letconvert_p=function|`Add(k,v)->ifpredkvthen[`Add(k,v)]else[]|`Delk->[`Delk]inletfilter_e=function|Setm->Set(M.filterpredm)|Patchp->Patch(List.concat(List.mapconvert_pp))inlete=React.E.mapfilter_e(eventm)infrom_event(M.filterpred(valuem))eend