123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151(* This file is free software, part of gen. See file "license" for more details. *)(** {1 Efficient Mutable Lists} *)type'agen=unit->'aoptiontype'aclonable=<gen:'agen;(** Generator of values tied to this copy *)clone:'aclonable;(** Clone the internal state *)>type'anode=|Nil|Consof'aarray*intref*'anoderef|Cons1of'a*'anoderef|Suspendof'agentype'at={start:'anoderef;(* first node. *)mutablechunk_size:int;max_chunk_size:int;}let_make~max_chunk_sizegen={start=ref(Suspendgen);chunk_size=8;max_chunk_size;}let_make_no_buffergen={start=ref(Suspendgen);chunk_size=1;max_chunk_size=1;}(* increment the size of chunks *)let_incr_chunk_sizemlist=ifmlist.chunk_size<mlist.max_chunk_sizethenmlist.chunk_size<-2*mlist.chunk_size(* read one chunk of input; return the corresponding node.
will potentially change [mlist.chunk_size]. *)let_read_chunkmlistgen=matchgen()with|None->Nil(* done *)|Somexwhenmlist.max_chunk_size=1->lettail=ref(Suspendgen)inletnode=Cons1(x,tail)innode|Somex->(* new list node *)letr=ref1inleta=Array.makemlist.chunk_sizexinlettail=ref(Suspendgen)inletstop=reffalseinletnode=Cons(a,r,tail)in(* read the rest of the chunk *)whilenot!stop&&!r<mlist.chunk_sizedomatchgen()with|None->tail:=Nil;stop:=true|Somex->a.(!r)<-x;incrr;done;_incr_chunk_sizemlist;node(* eager construction *)letof_gengen=letmlist=_make~max_chunk_size:4096geninletrec_fillprev=match_read_chunkmlistgenwith|Nil->prev:=Nil|Suspend_->assertfalse|Cons1(_,prev')asnode->prev:=node;_fillprev'|Cons(_,_,prev')asnode->prev:=node;_fillprev'in_fillmlist.start;mlist(* lazy construction *)letof_gen_lazy?(max_chunk_size=2048)?(caching=true)gen=ifcachingthenletmax_chunk_size=maxmax_chunk_size2in_make~max_chunk_sizegenelse_make_no_buffergenletto_genl=letcur=refl.startinleti=ref0inletrecnext()=match!!curwith|Nil->None|Cons1(x,l')->cur:=l';Somex|Cons(a,n,l')->if!i=!nthenbegincur:=l';i:=0;next()endelsebeginlety=a.(!i)inincri;Someyend|Suspendgen->letnode=_read_chunklgenin!cur:=node;next()innextletto_clonablel:'aclonable=letrecmakenodei=letcur=refnodeandi=refiinletrecnext()=match!!curwith|Nil->None|Cons(a,n,l')->if!i=!nthenbegincur:=l';i:=0;next()endelsebeginlety=a.(!i)ini:=!i+1;Someyend|Cons1(x,l')->cur:=l';Somex|Suspendgen->letnode=_read_chunklgenin(!cur):=node;next()inobjectmethodgen=nextmethodclone=make!cur!iendinmakel.start0