1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507(*
* DynArray - Resizeable Ocaml arrays
* Copyright (C) 2003 Brian Hurt
* Copyright (C) 2003 Nicolas Cannasse
* Copyright (C) 2008 David Teller
*
* 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
*)##V>=5##modulePervasives=Stdlibtyperesizer_t=currslots:int->oldlength:int ->newlength:int ->inttype'ainternexternalilen:'aintern->int="%obj_size"let idup(x:'aintern):'aintern=Obj.magic(Obj.dup(Obj.reprx))letimakelen=(Obj.magic(Obj.new_block0len):'aintern)external iget:'aintern->int->'a="%obj_field"externaliset:'aintern->int->'a->unit="%obj_set_field"type'at={mutablearr:'aintern;mutablelen:int;mutableresize:resizer_t;}letdummy_for_gc =Obj.magic0letbool_invariantst=t.len>=0&&t.len<=ilent.arr&&(* check that elements beyond t.len are free'd, no memory leak *)letrecchecki=ifi>=ilent.arr-1thentrueelseigett.arri==dummy_for_gc&&check(i+1)incheck t.lenletinvariantst=assert(bool_invariantst)type'amappable='attype'aenumerable ='atexceptionInvalid_arg ofint*string*stringletinvalid_arg nfp=raise(Invalid_arg(n,f,p))letlengthd=d.lenletexponential_resizer~currslots~oldlength:_~newlength=letrecdoublerx=ifx>=newlength thenxelsedoubler (x*2)inlet rechalferx=ifx/2<newlengththenxelsehalfer (x/2)inifnewlength=1then1elseifcurrslots=0thendoubler1elseifcurrslots <newlengththendoubler currslotselsehalfer currslotsletstep_resizerstep=ifstep<=0theninvalid_argstep"step_resizer""step";(fun~currslots~oldlength:_~newlength->ifcurrslots <newlength||newlength<(currslots-step)then(newlength+step-(newlength modstep))elsecurrslots)letconservative_exponential_resizer~currslots~oldlength~newlength=letrecdoublerx=ifx>=newlength thenxelsedoubler (x*2)inlet rechalferx=ifx/2<newlengththenxelsehalfer (x/2)inifcurrslots<newlengththenbeginifnewlength=1then1elseifcurrslots=0thendoubler1elsedoublercurrslotsendelseifoldlength <newlengththenhalfercurrslotselsecurrslotsletdefault_resizer=conservative_exponential_resizerletchangelen(d:'at)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!
*)letnewsize=ifr<newlenthennewlenelserinifnewsize<>oldsizethenbeginletnewarr=imakenewsizeinletcpylen=(ifnewlen<d.lenthennewlenelsed.len)infori=0tocpylen-1doisetnewarri(igetd.arri);done;d.arr<-newarr;end;d.len<-newlenletcompactd=ifd.len<>ilend.arrthenbeginletnewarr=imaked.leninfori=0tod.len-1doisetnewarri(igetd.arri)done;d.arr<-newarr;endletcreate_withresize={resize;len=0;arr=imake0;}(*$Q
(Q.list Q.small_int) (fun l -> \
let v = create_with exponential_resizer in List.iter (add v) l; \
bool_invariants v)
(Q.list Q.small_int) (fun l -> \
let v = create_with conservative_exponential_resizer in List.iter (add v) l; \
bool_invariants v)
(Q.list Q.small_int) (fun l -> \
let v = create_with (step_resizer 5) in List.iter (add v) l; \
bool_invariants v)
*)letcreate()={resize =default_resizer;len=0;arr=imake0;}(*$Q
(Q.list Q.small_int) (fun l -> \
let v = create() in List.iter (add v) l; \
bool_invariants v)
*)letsingletonx=leta={resize=default_resizer;len=1;arr=imake1;}iniseta.arr0x;a(*$T
to_list @@ singleton 42 = [42]
*)letmakeinitlen=ifinitlen<0theninvalid_arg initlen"make""size";{resize=default_resizer;len=0;arr=imakeinitlen;}letinitinitlenf=ifinitlen<0theninvalid_arg initlen"init""len";letarr=imakeinitleninfori=0toinitlen-1doisetarr i(fi)done;{resize=default_resizer;len=initlen;arr=arr;}(*$T
init 5 identity |> to_list = [0;1;2;3;4]
*)letset_resizerdresizer=d.resize<-resizerletget_resizerd=d.resizeletemptyd=d.len=0letgetdidx=ifidx<0||idx>=d.lentheninvalid_argidx"get""index";igetd.arridxletsetdidxv=ifidx<0||idx>=d.lentheninvalid_argidx"set""index";isetd.arridxv(* upd a i f= set a i (f @@ get a i)
Faster (avoids duplication of bounds checks) and more convenient. *)letupddidxf=ifidx<0||idx>=d.lentheninvalid_argidx"set""index";isetd.arridx(f(igetd.arridx))letfirstd=ifd.len=0theninvalid_arg0"first""<array len is 0>";igetd.arr0letlastd=ifd.len=0theninvalid_arg0"last""<array len is 0>";igetd.arr(d.len-1)(*$T letv = of_list [1;2;3;4] in set v 1 42; get v 1 = 42
let v = of_list [1;2;3;4] in set v 1 42; last v = 4
let v = of_list [1;2;3;4] in set v 1 42; first v = 1
let v = of_list [1;2;3;4] in upd v 1 succ; get v 1 = 3
*)letleftan=ifn<0||n>a.lentheninvalid_argn"left""len";letarr=imakeninfori=0ton-1doisetarri(igeta.arri)done;{resize=a.resize;len=n;arr=arr;}letrightan=ifn<0||n>a.lentheninvalid_argn"right""len";letarr=imakenin(* for i = a.len - n to a.len - 1 do *)leti=ref0inletj=ref(a.len-n)inwhile!i<ndoisetarr!i(igeta.arr!j);incri;incrj;done;{resize=a.resize;len=n;arr=arr;}(*$T
let v = left (of_list [1;2;3;4;5;6;7;8]) 3 in to_list v = [1;2;3]
let v = right (of_list [1;2;3;4;5;6;7;8]) 3 in to_list v = [6;7;8]
try let v = left (of_list [1;2;3]) 9 in ignore v; false with Invalid_arg _ -> true
try let v = right (of_list [1;2;3]) 9 in ignore v; false with Invalid_arg _ -> true
try let v = left (of_list [1;2;3]) (-1) in ignore v; false with Invalid_arg _ -> true
try let v = right (of_list [1;2;3]) (-1) in ignore v; false with Invalid_arg _ -> true
*)lethead=leftlettail an=ifn<0||n>a.lentheninvalid_argn"tail""pos";letlen=a.len-ninletarr=imakelenin(* for i = n to a.len - 1 do *)leti=ref0inletj=refninwhile!j<a.lendoisetarr!i(igeta.arr!j);incri;incrj;done;{resize=a.resize;len=len;arr=arr;}(*$T
let v = head (of_list [1;2;3;4;5;6;7;8]) 3 in to_list v = [1;2;3]
let v = tail (of_list [1;2;3;4;5;6;7;8]) 3 in to_list v = [4;5;6;7;8]
try let v = tail (of_list [1;2;3]) 9 in ignore v; false with Invalid_arg _ -> true
try let v = tail (of_list [1;2;3]) (-1) in ignore v; false with Invalid_arg _ -> true
*)letinsertdidxv=ifidx<0||idx>d.lentheninvalid_arg idx"insert""index";ifd.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.arridxv(*$T
let v= of_list [1;2;3;4] in insert v 2 10; to_list v = [1;2;10;3;4]
*)letadddv=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";letoldsize=ilend.arrin(* wedon't call 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=imakenewsizeinfori=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)dummy_for_gcend;d.len<-d.len-1(*$T
let v = of_list [1;2;3;4] in delete v 1; to_list v = [1;3;4]
*)letremove_atidxd=deletedidxletdelete_rangedidxlen=iflen<0theninvalid_arglen"delete_range""length";ifidx<0||idx+len>d.len theninvalid_arg idx"delete_range""index";letoldsize=ilend.arrin(* wedon't call changelen because we want to blit *)letr=d.resize~currslots:oldsize~oldlength:d.len~newlength:(d.len-len)inletnewsize=(ifr<d.len-lenthend.len-len elser)inifoldsize<>newsizethenbeginletnewarr=imakenewsizeinfori=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.arridummy_for_gcdone;end;d.len<-d.len-len(*$T
letv = of_list [1;2;3;4] in delete_range v 1 2; to_list v = [1;4]
let v = of_list [1;2;3;4] in delete_range v 1 0; to_list v = [1;2;3;4]
let v = of_list [1;2;3;4] in try delete_range v 4 2; false \
with Invalid_arg _ -> true
*)letcleard=d.len<-0;d.arr<-imake0(*$T
let v = of_list [1;2;3;4;5] in clear v; to_list v = []
*)letdelete_lastd=ifd.len<=0theninvalid_arg0"delete_last""<array len is 0>";(* erase for GC, in case changelen don't resize our array *)isetd.arr(d.len-1)dummy_for_gc;changelend(d.len-1)(*$T letv = of_list [1;2;3;4;5] in delete_last v; to_list v = [1;2;3;4]
*)letblitsrcsrcidxdstdstidxlen=iflen<0theninvalid_arglen"blit""len";ifsrcidx<0||srcidx+len>src.lentheninvalid_argsrcidx"blit""source index";ifdstidx<0||dstidx>dst.lentheninvalid_argdstidx"blit""dest index";letnewlen=dstidx+leninifnewlen >ilendst.arrthenbegin(* this case could be inlined so we don't blit on just-copied elements *)changelendstnewlenendelse beginifnewlen>dst.lenthendst.len <-newlen;end;(* same array ! we need to copy in reverse order *)ifsrc.arr==dst.arr&&dstidx>srcidxthenfori=len-1downto0doisetdst.arr(dstidx+i)(igetsrc.arr(srcidx+i));doneelsefori=0tolen-1doisetdst.arr(dstidx+i)(igetsrc.arr(srcidx+i));done(*$T
let v = of_list [1;2;3;4;5] and v2 = of_list [10;11] in \
blit v2 0 v 1 2; to_list v = [1;10;11;4;5]
*)letappendsrcdst=blitsrc0dstdst.lensrc.len(*$T
let v = of_list [1;2;3;4;5] and v2 = of_list [10;11] in \
append v2 v; to_list v = [1;2;3;4;5;10;11]
*)letto_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.arr i)done;arr;endletof_listlst=letsize=List.lengthlstinletarr=imakesizeinletrecloopidx=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_tag inletarr=(ifis_floatthenbeginletarr=imakesizeinfori=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;}(*$T
let v = of_list [1;2;3] in let v2 = copy v in \
set v 0 42; get v2 0 = 1
*)letsubsrcstartlen=iflen<0theninvalid_arglen"sub""len";ifstart<0||start+len>src.lentheninvalid_argstart"sub""start";letarr=imakeleninfori=0tolen-1doisetarri(igetsrc.arr(i+start));done;{resize=src.resize;len=len;arr=arr;}(*$T
let v = of_list [1;2;3;4;5] in \
let v2 = sub v 1 3 in to_list v2 = [2;3;4]
let v = of_list [1;2;3;4;5] in \
let v2 = sub v 0 1 in to_list v2 = [1]
let v = of_list [1;2;3;4;5] in \
let v2 = sub v 4 1 in to_list v2 = [5]
let v = of_list [1;2;3;4;5] in \
let v2 = sub v 2 0 in to_list v2 = []
let v = of_list [1;2;3;4;5] in \
try ignore @@ sub v (-1) 2; false with Invalid_arg _ -> true
let v = of_list [1;2;3;4;5] in \
try ignore @@ sub v 5 2; false with Invalid_arg _ -> true
let v = of_list [1;2;3;4;5] in \
try ignore @@ sub v 3 3; false with Invalid_arg _ -> true
let v = of_list [1;2;3;4;5] in \
try ignore @@ sub v 3 (-1); false with Invalid_arg _ -> true
*)letfillastartlenx=iflen <0theninvalid_arglen"fill""len";ifstart<0||start+len>a.len theninvalid_arg start"fill""start";fori=starttostart+len-1doiseta.arrixdone(*$T
let v = of_list [1;2;3;4;5] in \
fill v 1 3 0; to_list v = [1;0;0;0;5]
let v = of_list [1;2;3;4;5] in \
fill v 0 1 0; to_list v = [0;2;3;4;5]
let v = of_list [1;2;3;4;5] in \
fill v 4 1 0; to_list v = [1;2;3;4;0]
let v = of_list [1;2;3;4;5] in \
fill v 2 0 0; to_list v = [1;2;3;4;5]
let v = of_list [1;2;3;4;5] in \
try fill v (-1) 2 0; false with Invalid_arg _ -> true
let v = of_list [1;2;3;4;5] in \
try fill v 5 2 0; false with Invalid_arg _ -> true
let v = of_list [1;2;3;4;5] in \
try fill v 3 3 0; false with Invalid_arg _ -> true
let v = of_list [1;2;3;4;5] in \
try fill v 3 (-1) 0; false with Invalid_arg _ -> true
let v = of_list [1;2;3;4;5] in \
try fill v (-1) 2 0; false with Invalid_arg _ -> true
let v = of_list [1;2;3;4;5] in \
try fill v 5 2 0; false with Invalid_arg _ -> true
let v = of_list [1;2;3;4;5] in \
try fill v 3 3 0; false with Invalid_arg _ -> true
let v = of_list [1;2;3;4;5] in \
try fill v 3 (-1) 0; false with Invalid_arg _ -> true
*)letsplita=letn=a.leninletleft=makeninlet right=makeninfori=0ton-1doleta,b=igeta.arriinisetleft.arria;iset right.arribdone;left.len<-n;right.len<-n;(left,right)(*$T
let v = of_list [] in let l,r = split v in \
(to_list l, to_list r) = ([], [])
let v = of_list [(1,"a");(2,"b");(3,"c")] in let l,r = split v in \
(to_list l, to_list r) = ([1;2;3], ["a";"b";"c"])
*)letcombinea1a2=ifa1.len<> a2.lentheninvalid_arga1.len"DynArray.combine""array lengths differ";letarr=imakea1.leninfori=0toa1.len-1doisetarri(igeta1.arri,igeta2.arri)done;{resize=a1.resize;len=a1.len;arr=arr;}(*$T
let l,r = (of_list [], of_list []) in let c = combine l r in \
to_list c = []
let l, r = (of_list [1;2;3], of_list ["a";"b";"c"]) in let c = combine l r in \
to_list c = [(1,"a");(2,"b");(3,"c")]
try let l, r = (of_list [1;2;3], of_list ['a']) in \
ignore(combine l r); false \
with Invalid_arg _ -> true
*)letiterfd=leti=ref0inwhile!i<d.lendof(igetd.arr!i);incridone(*$T
let v = of_list [1;2;3] and v2 = create() in \
iter (add v2) v; to_list v2 = [1;2;3]
*)(* string_of_int and int_of_string seems useless but it
is because if you only manipulate integers, you aren't
likely to have segfaults even if the code is wrong *)(*$R iter
let n = 20 in
let acc = ref 0 in
let d = init n (fun i -> string_of_int i) in
iter (fun s -> assert (Obj.tag (Obj.repr s) = Obj.string_tag); acc := !acc + int_of_string s) d;
assert_bool "iter" (!acc = (n - 1) * n / 2)
*)(* checking the absence of segfault when the array shrinks *)(*$R iter
let n = 40 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
iter (fun s -> assert (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
if !i = 0 then
for _count = 0 to n * 4 / 5 do delete_last d done
) d
*)(* checking the absence of segfault when the array grows *)(*$R iter
let n = 40 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
iter (fun s -> assert (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
if !i = 0 then
for _count = 0 to n * 4 do add d "poi" done
) d
*)letiterifd=leti=ref0inwhile!i<d.lendof!i(igetd.arr!i);incridone(*$R iteri
let n = 20 in
let acc = ref 0 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
iteri (fun idx s -> assert (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
assert (idx = !i); acc := !acc + int_of_string s) d;
assert_bool "iteri" (!acc = (n - 1) * n / 2)
*)(*$R iteri
let n = 40 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
iteri (fun idx s -> assert (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
assert (idx = !i);
if !i = 0 then
for _count = 0 to n * 4 / 5 do delete_last d done
) d
*)(*$R iteri
let n = 40 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
iteri (fun idx s -> assert (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
assert (idx = !i);
if !i = 0 then
for _count = 0 to n * 4 do add d "poi" done
) d
*)(* Old implementation *)(*let filter f d =
let l = d.len in
let dest = make l in
let a2 = d.arr in
let p = ref 0 in (* p is index of next unused element *)
let i = ref 0 in
while !i < d.len && !i < l do
(* beware that the call to f might make lengthen d
in which case, if we iterate on the new elements
dest.array may be too short
so when some elements are added, we do not iterate on them
(test !i < len)
if some elements are removed, we are also careful not to
iterate on the removed elements (test !i < d.len)
*)
let x = iget a2 !i in
if f x then begin
iset dest.arr !p x;
incr p;
end;
incr i
done;
dest.len <- !p;
changelen dest !p;
dest*)(* Efficient implementation using BitSet, lifted from BatArray implementation of filter *)letfilterpa=letn=a.lenin(* Use a bitset to store which elements will be in the final array. *)letbs=BatBitSet.createninfori=0ton-1doifp(igeta.arri)thenBatBitSet.setbsidone;(* Allocate the final array and copy elements into it. *)letn'=BatBitSet.countbsinletj=ref0ininitn'(fun_->match BatBitSet.next_set_bitbs!jwith|Somei->j:=i+1;igeta.arri|None->(* not enough 1 bits - incorrect count? *)assertfalse)(*$T filter
let v = filter (fun x -> x mod 3 = 0) (of_list @@ BatList.range 1 `To 10) in \
to_list v = [3;6;9]
let v = filter (fun _ -> assert false) (create()) in \
to_list v = []
*)letfind_all=filterletfilteripa=letn=a.lenin(* Use a bitset to store which elements will be in the final array. *)letbs=BatBitSet.createninfori=0ton-1doifpi(igeta.arri)thenBatBitSet.setbsidone;(* Allocate the final array and copy elements into it. *)letn'=BatBitSet.countbsinletj=ref0ininitn'(fun_->match BatBitSet.next_set_bitbs!jwith|Somei->j:=i+1;igeta.arri|None->(* not enough 1 bits - incorrect count? *)assertfalse)(*$T filteri
let v = filteri (fun i x -> (i+x) mod 2 = 0) (of_list [1;2;3;4;0;1;2;3]) in \
to_list v = [0;1;2;3]
let v = filteri (fun _ _ -> assert false) (create()) in \
to_list v = []
*)letkeepfd=letresult=filterfdind.arr<-result.arr;d.len<-result.len(*$R keep
let e = create () in
add e "a";
add e "b";
keep ((=) "a") e;
assert_equal ~printer:(fun x -> x) (get e 0) "a"
*)letfilter_mapfd=letl=d.leninletdest=makelin(*Create the destination array with size [l]*)leta2=d.arrinletp=ref0inleti=ref0inwhile!i<d.len&&!i<ldo(matchf(igeta2!i)with|None->()|Somex->beginisetdest.arr!px;incrp;end);incridone;dest.len<-!p;changelen dest!p;(*Trim the destination array to the right size*)dest(*$R filter_map
let n = 20 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
let d = filter_map (fun s ->
assert (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
if !i mod 2 = 0 then Some (s ^ s) else None) d in
assert_bool "filter_map" (length d = n / 2);
let acc = ref true in
iteri (fun idx s -> acc := (!acc && (s = string_of_int (2 * idx) ^ string_of_int (2 * idx)))) d;
assert_bool "filter_map" !acc
*)(*$R filter_map
let n = 40 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
ignore (filter_map (fun s -> assert (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
if !i = 0 then
for _count = 0 to n * 4 / 5 do delete_last d done;
Some s
) d)
*)(*$R filter_map
let n = 40 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
ignore (filter_map (fun s -> assert (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
if !i = 0 then
for _count = 0 to n * 4 do add d "poi" done;
Some s
) d)
*)letpartitionpa=letn=a.lenin(* Use a bitset to store which elements will be in the final array. *)letbs=BatBitSet.createninfori=0ton-1doifp(igeta.arri)thenBatBitSet.setbsidone;(* Allocate the arrays and copy elements into them. *)letn'=BatBitSet.countbsinletpos=maken'inletneg=make(n-n')infori=0ton-1doifBatBitSet.membsithenaddpos(igeta.arri)elseaddneg(igeta.arri)done;(pos,neg)(*$T partition
let v,w = partition (fun x -> x mod 3 = 0) (of_list @@ BatList.range 1 `To 10) in \
(to_list v, to_list w) = ([3;6;9], [1;2;4;5;7;8;10])
let v,w = partition (fun _ -> assert false) (create()) in \
empty v && empty w
*)letfor_allpa=letn=a.leninletrecloopi=ifi=nthentrueelseifp(igeta.arri)thenloop(succi)elsefalseinloop0(*$T for_all
for_all (fun x -> x mod 2 = 0) (of_list [2;4;6]) = true
for_all (fun x -> x mod 2 = 0) (of_list [2;3;6]) = false
for_all (fun _ -> false) (create()) = true
*)letexistspa=letn=a.leninletrecloopi=ifi=nthenfalseelseifp(igeta.arri)thentrueelseloop(succi)inloop0(*$T exists
exists (fun x -> x mod 2 = 0) (of_list [1;4;5]) = true
exists (fun x -> x mod 2 = 0) (of_list [1;3;5]) = false
exists (fun _ -> false) (create()) = false
*)letmemxa=letn=a.leninletrecloopi=ifi=nthenfalseelseifx=igeta.arrithentrueelseloop(succi)inloop0(*$T memmem 2 (of_list [1;2;3]) = true
mem 2 (create()) = false
mem (ref 3) (of_list [ref 1; ref 2; ref 3]) = true
*)letmemqxa=letn=a.leninletrecloopi=ifi=nthenfalseelseifx==igeta.arrithentrueelseloop(succi)inloop0(*$T memq
memq 2 (of_list [1;2;3]) = true
memq 2 (create()) = false
memq (ref 3) (of_list [ref 1; ref 2; ref 3]) = false
*)letindex_ofpa=letrecloopi=ifi=a.lenthenraiseNot_foundelse ifp(igeta.arri)thenielseloop(succi)inloop0letfindi=index_of(*$T findi
findi (fun x -> x mod 3 = 0) (of_list [1;2;3;4;5;6]) = 2
try ignore @@ findi (fun x -> x mod 3 = 0) (of_list [1;2;4;5]); false \
with Not_found -> true
try ignore @@ findi (fun _ -> assert false) (create()); false \
with Not_found -> true
*)(* let find p a = iget a.arr (findi p a) *)letfindpa=letrecloopi=ifi=a.lenthenraiseNot_foundelse letx=igeta.arriinifpxthenxelseloop(succi)inloop0(*$T find
find (fun x -> x mod 3 = 0) (of_list [1;2;3;4;5;6]) = 3
try ignore @@ find (fun x -> x mod 3 = 0) (of_list [1;2;4;5]); false \
with Not_found -> true
try ignore @@ find (fun _ -> assert false) (create()); false \
with Not_found -> true
*)letmapfsrc=letlen=src.leninletarr =imakeleninleti=ref 0inwhile!i<src.len&&!i<lendoisetarr!i(f(igetsrc.arr!i));incr idone;{resize=src.resize;len=BatInt.minlensrc.len;arr=arr;}(*$R map
let n = 20 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
let res = map (fun s ->
assert_bool "DynArray.map1" (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
s ^ s) d in
assert_bool "DynArray.map2" (length res = n);
iteri (fun idx s -> assert_bool "DynArray.map3" (s ^ s = get res idx)) d
*)(*$R map
let n = 40 in
let newlen = n / 5 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
let res = map (fun s -> assert (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
if !i = 0 then
for _count = 0 to n - 1 - newlen do delete_last d done;
true
) d in
assert_bool "DynArray.map4" (length res = newlen)
(* could be something else if the implementation changed *)
*)(*$R map
let n = 40 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
let res = map (fun s -> assert (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
if !i = 0 then
for _count = 0 to n * 4 do add d "poi" done;
true
) d in
assert_bool "DynArray.map5" (length res = n)
(* could be something else if the implementation changed *)
*)letmapifsrc=letlen=src.leninletarr =imakeleninleti=ref 0inwhile!i<src.len&&!i<lendoisetarr!i(f!i(igetsrc.arr!i));incr idone;{resize=src.resize;len=BatInt.minlensrc.len;arr=arr;}(*$R mapi
let n = 20 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
let res = mapi (fun idx s ->
assert_bool "DynArray.map1" (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
assert_bool "DynArray.map2" (!i = idx);
s ^ s) d in
assert_bool "DynArray.map3" (length res = n);
iteri (fun idx s -> assert_bool "DynArray.map3" (s ^ s = get res idx)) d
*)(*$R mapi
let n = 40 in
let newlen = n / 5 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
let res = mapi (fun idx s -> assert (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
assert_bool "DynArray.mapi4" (!i = idx);
if !i = 0 then
for _count = 0 to n - 1 - newlen do delete_last d done;
true
) d in
assert_bool "DynArray.mapi5" (length res = newlen)
(* could be something else if the implementation changed *)
*)(*$R mapi
let n = 40 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
let res = mapi (fun idx s -> assert (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
assert_bool "DynArray.mapi6" (!i = idx);
if !i = 0 then
for _count = 0 to n * 4 do add d "poi" done;
true
) d in
assert_bool "DynArray.mapi7" (length res = n)
(* could be something else if the implementation changed *)
*)letmodifyfa=fori=0tolengtha-1doiseta.arri(f(igeta.arri))done(*$T modify
let a = (of_list [3;2;1]) in \
modify (fun x -> x + 1) a; to_list a = [4;3;2]
*)letmodifyifa=fori=0tolengtha-1doiseta.arri(fi(igeta.arri))done(*$T modifyi
let a = (of_list [3;2;1]) in \
modifyi (fun i x -> i * x) a; to_list a = [0;2;2]
*)letfold_leftfxa=letrecloopidxx=ifidx>=a.lenthenxelseloop(idx+1)(fx(igeta.arridx))inloop0xletfold_rightfax=letrecloopidxx=ifidx<0||idx>=a.lenthenxelseloop(idx-1)(f(iget a.arridx)x)inloop(a.len-1)x(*$R fold_right
let n = 20 in
let d = init n (fun i -> string_of_int i) in
let buffer = Buffer.create 10 in
let buffer2 = Buffer.create 10 in
let len = fold_right (fun s count ->
assert_bool "DynArray.fold_right1" (Obj.tag (Obj.repr s) = Obj.string_tag);
Buffer.add_string buffer s; count + 1) d 0 in
assert_bool "DynArray.fold_right2" (len = length d);
List.iter (fun s -> Buffer.add_string buffer2 s) (List.rev (to_list d));
assert_bool "DynArray.fold_right3" (Buffer.contents buffer = Buffer.contents buffer2)
*)(*$R fold_right
let n = 40 in
let newlen = n / 5 in
let d = init n (fun i -> string_of_int i) in
let i = ref (-1) in
ignore (fold_right (fun s () ->
assert (Obj.tag (Obj.repr s) = Obj.string_tag); incr i;
if !i = 0 then
for _count = 0 to n - 1 - newlen do delete_last d done
) d ())
*)letfold_leftifxa=letr=refxinfori=0toa.len-1dor:=f!ri(igeta.arri)done;!r(*$T fold_lefti
fold_lefti (fun a i x -> a + i * x) 1 (of_list [2;4;5]) = 1 + 0 + 4 + 10
fold_lefti (fun a i x -> a + i * x) 1 (create()) = 1
*)letfold_rightifax=letr=refxinfori=a.len-1downto0dor:=fi(igeta.arri)!rdone;!r(*$T fold_righti
fold_righti (fun i x a -> a + i * x) (of_list [2;4;5]) 1 = 1 + 0 + 4 + 10
fold_righti (fun i x a -> a + i * x) (create()) 1 = 1
*)letreducefa=ifa.len=0theninvalid_arga.len"DynArray.reduce""empty array";letacc=ref(igeta.arr 0)infori=1toa.len-1doacc:=f!acc(igeta.arri)done;!acc(*$T reduce reduce (+) (of_list [1;2;3]) = 6
reduce (fun _ -> assert false) (of_list [1]) = 1
try reduce (fun _ _ -> ()) (create()); false \
with Invalid_arg _ -> true
*)letreva=letn=a.len-1inletnewarr=imake(n+1)infori=0tondoisetnewarri(igeta.arr(n-i))done;{resize=a.resize;len=a.len;arr=newarr;}(*$T
let a = rev (of_list [1;3;2;5]) in to_list a = [5;2;3;1]
let a = rev (of_list [1;3;2;5;-1]) in to_list a = [-1;5;2;3;1]
let a = rev (create()) in empty a
*)letrev_in_placea=letn=a.len-1inletlim=a.len/2-1infori=0tolimdoletx=igeta.arr(n-i)iniseta.arr(n-i)(igeta.arri);iseta.arrixdone(*$T
let a = of_list [1;3;2;5] in rev_in_place a; \
to_list a = [5;2;3;1]
let a = of_list [1;3;2;5;-1] in rev_in_place a; \
to_list a = [-1;5;2;3;1]
let a = create() in rev_in_place a; \
empty a
*)letmaxa=reducePervasives.maxa(*$T
max (of_list [1;2;3]) = 3
max (of_list [2;3;1]) = 3
try ignore (max (create())); false \
with Invalid_arg _ -> true
*)letmina=reducePervasives.mina(*$T
min (of_list [1;2;3]) = 1
min (of_list [2;3;1]) = 1
try ignore (min (create())); false \
with Invalid_arg _ -> true
*)letmin_maxa=letn=a.leninifn=0theninvalid_arga.len"DynArray.min_max""empty array";letmini=ref(igeta.arr 0)inletmaxi=ref(igeta.arr 0)infori=1ton-1doletx=igeta.arriinifx>!maxithenmaxi:=x;ifx<!minithenmini:=xdone;(!mini,!maxi)(*$T min_max
min_max (of_list [1]) = (1, 1)
min_max (of_list [1;-2;10;3]) = (-2, 10)
try ignore (min_max (create())); false \
with Invalid_arg _ -> true
*)letsum=fold_left(+)0(*$T sum
sum (of_list [1;2;3]) = 6
sum (of_list [0]) = 0
*)letfsum=fold_left(+.)0.(*$T fsum
fsum (of_list [1.0;2.0;3.0]) = 6.0
fsum (of_list [0.0]) = 0.0
*)letkahan_suma=letsum=ref0.inlet err=ref0.inlet n=a.len-1infori=0tondoletx=igeta.arri-.!errinletnew_sum=!sum+.xinerr:=(new_sum-.!sum)-.x;sum:=new_sum +.0.;(* this suspicious +. 0. is added to help
the hand of the somewhat flaky unboxing optimizer;
it hopefully won't be necessary anymore
in a few OCaml versions *)done;!sum+.0.(*$Tkahan_sum
kahan_sum (create()) = 0.
kahan_sum (of_list [1.;2.]) = 3.
let n, x = 1_000, 1.1 in \
Float.approx_equal (float n *. x) (kahan_sum (init n (fun _ -> x)))
*)letavga=(float_of_int(suma))/.(float_of_int(lengtha))(*$T avg
avg (of_list [1;2;3]) = 2.
avg (of_list [0]) = 0.
*)letfavga=(fsuma)/.(float_of_int(lengtha))(*$T favg
favg (of_list [1.0; 2.0; 3.0]) = 2.0
favg (of_list [0.0]) = 0.0
*)letiter2fa1a2=ifa1.len<> a2.lenthen invalid_arg a1.len"DynArray.iter2""array lengths differ";fori=0toa1.len-1dof(igeta1.arri)(igeta2.arri);done(*$T iter2
let x = ref 0 in \
iter2 (fun a b -> x := !x + a*b) (of_list [1;2;3]) (of_list [4;-5;6]); \
!x = 12
try iter2 (fun _ _ -> ()) (of_list [1]) (of_list [1;2;3]); false \
with Invalid_arg _ -> true
try iter2 (fun _ _ -> ()) (of_list [1]) (of_list []); false \
with Invalid_arg _ -> true
*)letiter2ifa1a2=ifa1.len<> a2.lentheninvalid_arga1.len"DynArray.iter2i""array lengths differ";fori=0toa1.len-1dofi(igeta1.arri)(igeta2.arri);done(*$T iter2i
let x = ref 0 in \
iter2i (fun i a b -> x := !x + a*b + i) (of_list [1;2;3]) (of_list [4;-5;6]); \
!x = 15
try iter2i (fun _ _ _ -> ()) (of_list [1]) (of_list [1;2;3]); false \
with Invalid_arg _ -> true
try iter2i (fun _ _ _ -> ()) (of_list [1]) (of_list []); false \
with Invalid_arg _ -> true
*)letfor_all2pa1a2=letn=a1.leninifa2.len<>ntheninvalid_arga1.len"DynArray.for_all2""array lengths differ";letrecloopi=ifi=nthentrueelseifp(igeta1.arri)(igeta2.arri)thenloop(succi)elsefalseinloop0(*$T for_all2
for_all2 (=) (of_list [1;2;3]) (of_list [3;2;1]) = false
for_all2 (=) (of_list [1;2;3]) (of_list [1;2;3]) = true
for_all2 (<>) (of_list [1;2;3]) (of_list [3;2;1]) = false
try ignore (for_all2 (=) (of_list [1;2;3]) (of_list [1;2;3;4])); false \
with Invalid_arg _ -> true
try ignore (for_all2 (=) (of_list [1;2]) (of_list [])); false \
with Invalid_arg _ -> true
*)letexists2pa1a2=letn=a1.leninifa2.len<>ntheninvalid_arga1.len"DynArray.exists2""array lengths differ";letrecloopi=ifi=nthenfalseelseifp(igeta1.arri)(igeta2.arri)thentrueelseloop(succi)inloop0(*$T exists2
exists2 (=) (of_list [1;2;3]) (of_list [3;2;1])
exists2 (<>) (of_list [1;2;3]) (of_list [1;2;3]) = false
try ignore (exists2 (=) (of_list [1;2]) (of_list [3])); false \
with Invalid_arg _ -> true
*)letmap2fa1a2=letn=a1.leninifa2.len<>ntheninvalid_arga1.len"DynArray.map2""array lengths differ";initn(funi->f(igeta1.arri)(igeta2.arri))(*$T map2
let v = map2 (-) (of_list [1;2;3]) (of_list [6;3;1]) in to_list v = [-5;-1;2]
let v = map2 (-) (of_list [2;4;6]) (of_list [1;2;3]) in to_list v = [1;2;3]
try ignore (map2 (-) (of_list [2;4]) (of_list [1;2;3])); false \
with Invalid_arg _ -> true
try ignore (map2 (-) (of_list [2;4]) (of_list [3])); false \
with Invalid_arg _ -> true
*)letmap2ifa1a2=letn=a1.leninifa2.len<>ntheninvalid_arga1.len"DynArray.map2i""array lengths differ";initn(funi->fi(igeta1.arri)(igeta2.arri))(*$T map2i
let v = map2i (fun i a b -> a-b + i) (of_list [1;2;3]) (of_list [6;3;1]) in to_list v = [-5;0;4]
let v = map2i (fun i a b -> a-b + i) (of_list [2;4;6]) (of_list [1;2;3]) in to_list v = [1;3;5]
try ignore (map2i (fun i a b -> a-b + i) (of_list [2;4]) (of_list [1;2;3])); false \
with Invalid_arg _ -> true
try ignore (map2i (fun i a b -> a-b + i) (of_list [2;4]) (of_list [3])); false \
with Invalid_arg _ -> true
*)letcartesian_producta1a2=letna=a1.leninlet nb=a2.lenininit(na*nb)(funj->leti=j/nbin(igeta1.arri,igeta2.arr(j-i*nb)))(*$T cartesian_product
let a = cartesian_product (of_list [1;2]) (of_list ["a";"b"]) in \
to_list a = [(1,"a"); (1,"b"); (2,"a"); (2,"b")]
*)letenumd=letrecmakestart=letidxref=refstartinletnext()=if!idxref>=d.lenthenraiseBatEnum.No_more_elementselseletretval=igetd.arr!idxref inincridxref;retvalandcount()=if!idxref>=d.lenthen0elsed.len-!idxrefandclone()=make!idxrefinBatEnum.make~next:next~count:count~clone:cloneinmake0letof_enume=ifBatEnum.fast_countethenbeginletc=BatEnum.counteinletarr=imakecinBatEnum.iteri(funix->isetarrix)e;{resize=default_resizer;len=c;arr=arr;}endelseletd=make0inBatEnum.iter(addd)e;d(*$Q(Q.list Q.small_int) (fun l -> \
let v = of_list l in \
enum v |> of_enum |> to_list = l)
*)letrangexs=BatEnum.(--^)0(xs.len)module Exceptionless=structletfindpa=trySome(findpa)withNot_found->Noneletfindipa=trySome(findipa)withNot_found->Noneendletunsafe_getan=igeta.arrnletunsafe_setanx=iseta.arrnxletunsafe_updanf=iseta.arrn(f(igeta.arrn))letprint?(first="[|")?(last="|]")?(sep="; ")print_a out t=BatEnum.print ~first~last~sepprint_a out (enum t)(*$T
Printf.sprintf2 "%a" (print Int.print) (of_list [1;2]) = "[|1; 2|]"
Printf.sprintf2 "%a" (print Int.print) (of_list []) = "[||]"
*)