123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451(*
* DynArray - Resizeable Ocaml arrays
* Copyright (C) 2003 Brian Hurt
* 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
*)typeresizer_t=currslots:int->oldlength:int->newlength:int->inttype'ainternexternalilen:'aintern->int="%obj_size"letidup(x:'aintern)=ifilenx=0thenxelse(Obj.magic(Obj.dup(Obj.reprx)):'aintern)letimaketaglen=(Obj.magic(Obj.new_blocktaglen):'aintern)externaliget:'aintern->int->'a="%obj_field"externaliset:'aintern->int->'a->unit="%obj_set_field"type'at={mutablearr:'aintern;mutablelen:int;mutableresize:resizer_t;}exceptionInvalid_arg ofint*string*stringlet invalid_argnfp=raise(Invalid_arg(n,f,p))letlengthd=d.lenletexponential_resizer~currslots~oldlength~newlength=letrec doublerx=ifx>=newlengththenxelsedoubler(x*2)inletrechalferx=ifx/2<newlengththenxelsehalfer(x/2)inifnewlength=1then1elseifcurrslots=0thendoubler1elseifcurrslots<newlengththendoublercurrslotselsehalfercurrslotsletstep_resizerstep=ifstep<=0theninvalid_argstep"step_resizer""step";(fun~currslots~oldlength~newlength->ifcurrslots<newlength||newlength<(currslots-step)then(newlength +step-(newlengthmodstep))elsecurrslots)letconservative_exponential_resizer~currslots~oldlength~newlength=letrec doublerx=ifx>=newlengththenxelsedoubler(x*2)inletrechalferx=ifx/2<newlengththenxelsehalfer(x/2)inifcurrslots<newlengththenbeginifnewlength =1then1elseifcurrslots=0thendoubler1elsedoubler currslotsendelseifoldlength<newlengththenhalfercurrslotselsecurrslotsletdefault_resizer=conservative_exponential_resizerletchangelen(d:'at)newlen=ifnewlen>Sys.max_array_lengththeninvalid_argnewlen"changelen""newlen";letoldsize=ilend.arrinletr=d.resize~currslots:oldsize~oldlength:d.len~newlength:newlenin(* We require the size to be at least large enough to hold the number
* of elements we know we need!
* Also be sure not to exceed max_array_length
*)letnewsize=ifr<newlenthennewlenelseminSys.max_array_lengthrinifnewsize<>oldsizethenbeginletnewarr =imake0newsizeinletcpylen=(ifnewlen<d.lenthennewlenelsed.len)infor i=0tocpylen-1doisetnewarri(igetd.arri);done;d.arr<-newarr;end;d.len<-newlenletcompactd=ifd.len<>ilend.arrthenbeginletnewarr=imake0d.leninfori=0tod.len-1doisetnewarri(igetd.arri)done;d.arr<-newarr;endletcreate()={resize=default_resizer;len=0;arr=imake00;}letmakeinitsize=ifinitsize<0theninvalid_arginitsize"make""size";{resize=default_resizer;len=0;arr=imake0initsize;}letinitinitlenf=ifinitlen<0theninvalid_arginitlen"init""len";letarr =imake0initleninfori=0toinitlen-1doisetarri(fi)done;{resize=default_resizer;len=initlen;arr=arr;}letset_resizerdresizer=d.resize<-resizerletget_resizerd=d.resizeletemptyd=d.len=0letgetdidx=ifidx<0||idx>=d.lentheninvalid_argidx"get""index";igetd.arridxletlastd=ifd.len=0theninvalid_arg0"last""<array len is 0>";igetd.arr(d.len-1)letsetdidxv=ifidx<0||idx>=d.lentheninvalid_arg idx"set""index";isetd.arridxvletinsertdidxv=ifidx<0||idx>d.lentheninvalid_argidx"insert""index";if d.len=ilend.arrthenchangelend(d.len+1)elsed.len<-d.len+1;ifidx<d.len-1thenbeginfori=d.len-2downtoidxdoisetd.arr(i+1)(igetd.arri)done;end;isetd.arridxvletadddv=ifd.len=ilend.arrthenchangelend(d.len+1)elsed.len<-d.len+1;isetd.arr(d.len-1)vletdeletedidx=ifidx<0||idx>=d.lentheninvalid_argidx"delete""index";let oldsize=ilend.arrin(* we don'tcall changelen because we want to blit *)letr=d.resize~currslots:oldsize~oldlength:d.len~newlength:(d.len-1)inletnewsize=(ifr<d.len-1thend.len-1elser)inifoldsize<>newsizethenbeginletnewarr =imake0newsizeinfori=0toidx -1doisetnewarri(igetd.arri);done;fori=idxtod.len-2doisetnewarri(igetd.arr(i+1));done;d.arr<-newarr;endelsebeginfori=idxtod.len-2doisetd.arri(igetd.arr(i+1));done;isetd.arr(d.len-1)(Obj.magic0)end;d.len<-d.len-1letdelete_rangedidxlen=iflen<0then invalid_arg len"delete_range""length";ifidx<0||idx+len>d.lentheninvalid_argidx"delete_range""index";letoldsize=ilend.arrin(* we don'tcall changelen because we want to blit *)letr=d.resize~currslots:oldsize~oldlength:d.len~newlength:(d.len-len)inletnewsize=(ifr<d.len-lenthend.len-lenelser)inifoldsize<>newsizethenbeginletnewarr =imake0newsizeinfori=0toidx -1doisetnewarri(igetd.arri);done;fori=idxtod.len-len-1doisetnewarri(igetd.arr(i+len));done;d.arr <-newarr;endelsebeginfori=idxtod.len-len-1doisetd.arri(igetd.arr(i+len));done;fori=d.len-lentod.len-1doisetd.arri(Obj.magic0)done;end;d.len<-d.len-lenletcleard=d.len <-0;d.arr<-imake00letdelete_lastd=ifd.len<=0then invalid_arg0"delete_last""<array len is 0>";(* erase for GC, in case changelen don't resize our array *)isetd.arr(d.len-1)(Obj.magic0);changelend(d.len-1)letrecblitsrcsrcidxdstdstidxlen=iflen<0then invalid_arg len"blit""len";ifsrcidx <0||srcidx+len>src.lentheninvalid_argsrcidx"blit""source index";ifdstidx<0||dstidx>dst.lentheninvalid_argdstidx"blit""dest index";letnewlen=dstidx+leninif newlen>ilendst.arrthenbegin(* this case could be inlined so we don't blit on just-copied elements *)changelendstnewlenendelsebeginifnewlen>dst.lenthendst.len<-newlen;end;(* same array ! we need to copy in reverse order *)ifsrc.arr==dst.arr&&dstidx>srcidx thenfori=len-1downto0doisetdst.arr(dstidx+i)(igetsrc.arr(srcidx+i));doneelsefori=0tolen-1doisetdst.arr(dstidx+i)(igetsrc.arr(srcidx+i));doneletappend srcdst=blitsrc0dstdst.lensrc.lenletto_listd=letrecloopidxaccum=ifidx<0thenaccumelseloop(idx-1)(igetd.arridx::accum)inloop(d.len-1)[]letto_arrayd=ifd.len=0thenbegin(* since the empty array is an atom, we don't care if float or not *)[||]endelsebeginletarr=Array.maked.len(igetd.arr0)infori=1tod.len-1doArray.unsafe_setarri(igetd.arri)done;arr;endletof_listlst=letsize=List.lengthlstinletarr=imake0sizeinlet recloopidx=function|h:: t->isetarridxh;loop(idx+1)t|[]->()inloop0lst;{resize=default_resizer;len=size;arr=arr;}letof_arraysrc =letsize=Array.lengthsrcinletis_float=Obj.tag(Obj.reprsrc)=Obj.double_array_taginletarr=(ifis_floatthenbeginletarr=imake0sizeinfori=0tosize-1doisetarri(Array.unsafe_getsrci);done;arrendelse(* copy the fields *)idup(Obj.magicsrc:'aintern))in{resize=default_resizer;len=size;arr=arr;}letcopysrc={resize=src.resize;len=src.len;arr=idupsrc.arr;}letsubsrcstartlen=iflen<0then invalid_arg len"sub""len";ifstart<0||start+len>src.lentheninvalid_argstart"sub""start";letarr=imake0leninfor i=0tolen-1doisetarri(igetsrc.arr(i+start));done;{resize =src.resize;len=len;arr=arr;}letiterfd=fori=0tod.len-1dof(igetd.arri)doneletiterifd=fori=0tod.len-1dofi(igetd.arri)doneletfilterfd=letl=d.leninleta=imake0linleta2=d.arrinletp=ref0infori=0tol-1doletx=igeta2iiniffxthenbeginiseta!px;incrp;end;done;d.len<-!p;d.arr<-aletindex_offd=letrecloopi=ifi>=d.lenthenraiseNot_foundelseiff(igetd.arri)thenielseloop(i+1)inloop0letmapfsrc=letarr=imake 0src.leninfori=0tosrc.len-1doisetarri(f(igetsrc.arri))done;{resize=src.resize;len=src.len;arr=arr;}letmapifsrc=letarr=imake 0src.leninfori=0tosrc.len-1doisetarri(fi(igetsrc.arri))done;{resize=src.resize;len=src.len;arr=arr;}letfold_leftfxa=letrecloopidxx=ifidx>=a.lenthenxelseloop(idx+1)(fx(igeta.arridx))inloop0xlet fold_rightfax=letrecloopidxx=ifidx<0thenxelseloop(idx-1)(f(igeta.arridx)x)inloop(a.len -1)xletenumd=letrecmakestart=letidxref=ref 0inletnext ()=if!idxref>=d.lenthenraiseEnum.No_more_elementselseletretval=igetd.arr!idxrefinincridxref;retvaland count()=if!idxref>=d.lenthen0elsed.len-!idxrefandclone()=make!idxrefinEnum.make~next:next~count:count~clone:cloneinmake0letof_enume=ifEnum.fast_countethenbeginletc=Enum.counteinletarr=imake0cinEnum.iteri(funix->isetarrix)e;{resize =default_resizer;len=c;arr=arr;}endelseletd=make0inEnum.iter(addd)e;dletunsafe_getan=igeta.arrnletunsafe_setanx=iseta.arrnx