123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378(*
* Enum - Enumeration over abstract collection of elements.
* Copyright (C) 2003 Nicolas Cannasse
*
* 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
*)type'at={mutablecount:unit->int;mutablenext:unit->'a;mutableclone:unit->'at;mutablefast:bool;}(* raised by 'next' functions, should NOT go outside the API *)exceptionNo_more_elementslet_dummy()=assertfalseletmake~next~count~clone={count=count;next=next;clone=clone;fast=true;}letrecinitnf=ifn<0theninvalid_arg"Enum.init";letcount=refnin{count=(fun()->!count);next=(fun()->match!countwith|0->raiseNo_more_elements|_->decrcount;f(n-1-!count));clone=(fun ()->init!countf);fast=true;}letrecempty()={count =(fun()->0);next=(fun()->raiseNo_more_elements);clone=(fun()->empty());fast=true;}type'a_mut_list={hd:'a;mutabletl:'a_mut_list;}letforcet=letreccloneenumcount=letenum=ref!enumand count =ref!countin{count =(fun()->!count);next=(fun ()->match!enumwith|[]->raiseNo_more_elements|h::t->decrcount;enum:=t;h);clone=(fun()->letenum=ref!enumandcount=ref!countincloneenumcount);fast=true;}inletcount=ref0inlet_empty=Obj.magic[]inletrecloop dst=letx={hd =t.next();tl=_empty}inincrcount;dst.tl<-x;loopxinletenum=ref_emptyin(tryenum :={hd=t.next();tl=_empty};incrcount;loop!enum;withNo_more_elements ->());lettc=clone(Obj.magicenum)countint.clone<-tc.clone;t.next<- tc.next;t.count<- tc.count;t.fast<- trueletfromf=lete={next=f;count=_dummy;clone=_dummy;fast=false;}ine.count<-(fun()->forcee;e.count());e.clone<-(fun()->forcee;e.clone());eletfrom2nextclone=lete={next=next;count=_dummy;clone=clone;fast=false;}ine.count<-(fun()->forcee;e.count());eletnextt=t.next()letgett=trySome(t.next())withNo_more_elements->Noneletpushte=letrecmaket=letfnext=t.nextinlet fcount=t.countinletfclone=t.cloneinletnext_called=reffalseint.next <-(fun()->next_called:=true;t.next<-fnext;t.count<-fcount;t.clone<-fclone;e);t.count<-(fun()->letn=fcount()inif!next_called thennelsen+1);t.clone<-(fun()->lettc=fclone()inifnot!next_calledthenmaketc;tc);inmaketletpeekt=matchgettwith|None->None|Somex->pushtx;Somexletjunkt=tryignore(t.next())withNo_more_elements->()letis_emptyt=ift.fastthent.count()=0elsepeekt=Noneletcountt=t.count()letfast_countt=t.fastletclonet=t.clone()letiterft=letrecloop()=f(t.next());loop();intryloop();withNo_more_elements ->()letiterift=letrecloopidx=fidx(t.next());loop(idx+1);intryloop0;withNo_more_elements ->()letiter2ftu=letpush_t=refNoneinlet recloop()=push_t:=None;lete=t.next()inpush_t:=Somee;fe(u.next());loop()intryloop()withNo_more_elements ->match!push_twith|None->()|Somee->pushteletiter2iftu=letpush_t=refNoneinlet recloopidx=push_t:=None;lete=t.next()inpush_t:=Somee;fidxe(u.next());loop(idx+1)intryloop0withNo_more_elements->match!push_twith|None->()|Somee->pushteletfoldfinitt=letacc=refinitinlet recloop()=acc:=f(t.next())!acc;loop()intryloop()withNo_more_elements->!accletfoldifinitt=letacc=refinitinlet recloopidx=acc:=fidx (t.next())!acc;loop(idx+1)intryloop0withNo_more_elements->!accletfold2finittu=letacc=refinitinlet push_t=refNoneinlet recloop()=push_t:=None;lete=t.next()inpush_t:=Somee;acc:= fe(u.next())!acc;loop()intryloop()withNo_more_elements->match!push_twith|None->!acc|Somee->pushte;!accletfold2ifinittu=letacc=refinitinlet push_t=refNoneinlet recloopidx=push_t:=None;lete=t.next()inpush_t:=Somee;acc:= fidxe(u.next())!acc;loop(idx+1)intryloop0withNo_more_elements->match!push_twith|None->!acc|Somee->pushte;!accletfindft=letrecloop()=letx=t.next()iniffxthenxelseloop()intryloop()withNo_more_elements->raiseNot_foundletrecmapft={count=t.count;next=(fun()->f(t.next()));clone=(fun()->mapf(t.clone()));fast=t.fast;}letrecmapift=letidx=ref(-1)in{count =t.count;next=(fun()->incridx;f!idx(t.next()));clone=(fun()->mapif(t.clone()));fast=t.fast;}letrecfilterft=letrecnext()=letx=t.next()iniffxthenxelsenext()infrom2next(fun()->filterf(t.clone()))letrecfilter_mapft=letrecnext()=matchf(t.next())with|None->next()|Somex->xinfrom2next(fun()->filter_mapf(t.clone()))letrecappendtatb=lett={count=(fun()->ta.count()+tb.count());next=_dummy;clone=(fun()->append(ta.clone())(tb.clone()));fast=ta.fast&&tb.fast;}int.next<-(fun()->tryta.next()withNo_more_elements->(* add one indirection because tb can mute *)t.next<-(fun()->tb.next());t.count<-(fun()->tb.count());t.clone<-(fun()->tb.clone());t.fast<-tb.fast;t.next());tletrecconcatt=letconcat_ref=ref_dummyinletrecconcat_next()=lettn=t.next()inconcat_ref:=(fun()->trytn.next()withNo_more_elements->concat_next());!concat_ref ()inconcat_ref :=concat_next;from2(fun()->!concat_ref())(fun()->concat(t.clone()))