123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718(* This file is free software, part of containers. See file "license" for more details. *)(** {1 Growable, mutable vector} *)typerw=[`RW]typero=[`RO]type'aiter=('a->unit)->unittype'agen=unit->'aoptiontype'aequal='a->'a->booltype'aord='a->'a->inttype'aprinter=Format.formatter->'a->unittype('a,'mut)t={mutablesize:int;mutablevec:'aarray;}(** A vector of 'a. *)type'avector=('a,rw)ttype'aro_vector=('a,ro)texternalas_float_arr:'aarray->floatarray="%identity"externalas_obj_arr:'aarray->Obj.tarray="%identity"letfill_with_junk_(a:_array)ilen:unit=ifObj.(tag(repra)=double_array_tag)thenArray.fill(as_float_arra)ilen0.elseArray.fill(as_obj_arra)ilen(Obj.repr())letfreezev={size=v.size;vec=v.vec}letfreeze_copyv={size=v.size;vec=Array.subv.vec0v.size}letcreate()={size=0;vec=[||]}letcreate_with?(capacity=128)x=letvec=Array.makecapacityxinfill_with_junk_vec0capacity;{size=0;vec}letreturnx={size=1;vec=[|x|]}letmakenx={size=n;vec=Array.makenx}letinitnf={size=n;vec=Array.initnf}(* is the underlying array empty? *)let[@inline]array_is_empty_v=Array.lengthv.vec=0(* next capacity, if current one is [n] *)let[@inline]next_grow_n=minSys.max_array_length(n+(nlsr1)+2)(* resize the underlying array using x to temporarily fill the array *)letresize_vnewcapacityx=assert(newcapacity>=v.size);assert(not(array_is_empty_v));letnew_vec=Array.makenewcapacityxinArray.blitv.vec0new_vec0v.size;fill_with_junk_new_vecv.size(newcapacity-v.size);v.vec<-new_vec;()(* grow the array, using [x] as a filler if required *)letgrow_with_v~filler:x=ifarray_is_empty_vthen(letlen=4inv.vec<-Array.makelenx;(* do not really use [x], it was just for knowing the type *)fill_with_junk_v.vec0len)else(letn=Array.lengthv.vecinletsize=next_grow_ninifsize=ntheninvalid_arg"vec: can't grow any further";resize_vsizev.vec.(0))(* v is not empty; ensure it has at least [size] slots.
Use a doubling-size strategy so that calling many times [ensure] will
behave well *)letensure_assuming_not_empty_v~size=ifsize>Sys.max_array_lengththeninvalid_arg"vec.ensure: size too big"elseifsize<Array.lengthv.vecthen()(* nothing to do *)else(letn=ref(Array.lengthv.vec)inwhile!n<sizedon:=next_grow_!ndone;resize_v!nv.vec.(0))letensure_with~initvsize=ifarray_is_empty_vthen(v.vec<-Array.makesizeinit;fill_with_junk_v.vec0size)elseensure_assuming_not_empty_v~sizeletensurevsize=ifnot(array_is_empty_v)thenensure_assuming_not_empty_v~sizelet[@inline]clearv=v.size<-0letclear_and_resetv=v.size<-0;v.vec<-[||](* TODO*)(*
let v = create() in
let a = Weak.create 1 in
push v ("hello"^"world");
Weak.set a 0 (Some (get v 0));
Gc.full_major(); Gc.compact();
assert_bool "is alive" (Weak.check a 0);
Gc.full_major(); Gc.compact();
assert_equal None (Weak.get a 0);
*)let[@inline]is_emptyv=v.size=0[@@@ifge4.13]let[@inline]push_unsafe_vx=Sys.opaque_identity(Array.unsafe_setv.vecv.sizex);v.size<-v.size+1[@@@else_]let[@inlinenever]push_unsafe_vx=Array.unsafe_setv.vecv.sizex;v.size<-v.size+1[@@@endif]letpushvx=ifv.size=Array.lengthv.vecthengrow_with_v~filler:x;push_unsafe_vxletresize_withvfsize=ifsize<0theninvalid_arg"Vec.resize_with";ifArray.lengthv.vec=0then(letnew_vec=Array.initsizefinv.vec<-new_vec;v.size<-size)else(ensure_assuming_not_empty_v~size;let{size=cur_size;vec}=vinfori=cur_sizetosize-1doArray.unsafe_setveci(fi)done;assert(size<=Array.lengthv.vec);v.size<-size)letresize_with_initv~initsize=ifsize<0theninvalid_arg"Vec.resize_with_init";ifArray.lengthv.vec=0then(letvec=Array.makesizeinitinv.vec<-vec;v.size<-size)else(ensure_assuming_not_empty_v~size;(* nothing will change [v] *)fori=v.sizetosize-1doArray.unsafe_setv.veciinitdone;v.size<-size)(** Add all elements of b to a *)letappendab=ifarray_is_empty_athenifarray_is_empty_bthen()else(a.vec<-Array.copyb.vec;a.size<-b.size)else(ensure_assuming_not_empty_a~size:(a.size+b.size);assert(Array.lengtha.vec>=a.size+b.size);Array.blitb.vec0a.veca.sizeb.size;a.size<-a.size+b.size)[@@@ifge4.13]let[@inline]getvi=ifi<0||i>=v.sizetheninvalid_arg"CCVector.get";(* NOTE: over eager inlining seems to miscompile for int32 at least (#454) *)Sys.opaque_identity(Array.unsafe_getv.veci)let[@inline]setvix=ifi<0||i>=v.sizetheninvalid_arg"CCVector.set";Array.unsafe_setv.vecix[@@@else_]let[@inlinenever]getvi=ifi<0||i>=v.sizetheninvalid_arg"CCVector.get";Array.unsafe_getv.vecilet[@inlinenever]setvix=ifi<0||i>=v.sizetheninvalid_arg"CCVector.set";Array.unsafe_setv.vecix[@@@endif]letremove_and_shiftvi=ifi<0||i>=v.sizetheninvalid_arg"CCVector.remove";(* if v.(i) not the last element, then put last element at index i *)ifi<v.size-1thenArray.blitv.vec(i+1)v.veci(v.size-i-1);(* remove one element *)v.size<-v.size-1;fill_with_junk_v.vecv.size1letremove_unorderedvi=ifi<0||i>=v.sizetheninvalid_arg"CCVector.remove_unordered";(* if v.(i) not the last element, then put last element at index i *)ifi<v.size-1thenv.vec.(i)<-v.vec.(v.size-1);(* remove one element *)v.size<-v.size-1;fill_with_junk_v.vecv.size1letinsertvix=(* Note that we can insert at i=v.size *)ifi<0||i>v.sizetheninvalid_arg"CCVector.insert";ifv.size=Array.lengthv.vecthengrow_with_v~filler:x;(* Shift the following elements, then put the element at i *)ifi<v.sizethenArray.blitv.veciv.vec(i+1)(v.size-i);v.vec.(i)<-x;v.size<-v.size+1let[@inline]append_iterai=i(funx->pushax)letappend_seqaseq=Seq.iter(funx->pushax)seqletappend_arrayab=letlen_b=Array.lengthbinifarray_is_empty_athen(a.vec<-Array.copyb;a.size<-len_b)else(ensure_assuming_not_empty_a~size:(a.size+len_b);Array.blitb0a.veca.sizelen_b;a.size<-a.size+len_b)letappend_listab=matchbwith|[]->()|x::_->(* need to push at least one elem *)letlen_a=a.sizeinletlen_b=List.lengthbinensure_with~init:xa(len_a+len_b);List.iter(push_unsafe_a)b;()letrecappend_genab=matchb()with|None->()|Somex->pushax;append_genabletequaleqv1v2=v1.size=v2.size&&letn=v1.sizeinletrecchecki=i=n||(eq(getv1i)(getv2i)&&check(i+1))incheck0letcomparecmpv1v2=letn=minv1.sizev2.sizeinletrecchecki=ifi=nthencomparev1.sizev2.sizeelse(letc=cmp(getv1i)(getv2i)inifc=0thencheck(i+1)elsec)incheck0exceptionEmptyletpop_exnv=ifv.size=0thenraiseEmpty;letnew_size=v.size-1inv.size<-new_size;letx=v.vec.(new_size)in(* free last element *)fill_with_junk_v.vecnew_size1;xletpopv=trySome(pop_exnv)withEmpty->Nonelet[@inline]topv=ifv.size=0thenNoneelseSome(Array.unsafe_getv.vec(v.size-1))let[@inline]top_exnv=ifv.size=0thenraiseEmpty;(* NOTE: over eager inlining seems to miscompile for int32 at least (#454) *)Sys.opaque_identity(Array.unsafe_getv.vec(v.size-1))let[@inline]copyv={size=v.size;vec=Array.subv.vec0v.size}lettruncatevn=letold_size=v.sizeinifn<old_sizethen(v.size<-n;(* free elements by erasing them *)fill_with_junk_v.vecn(old_size-n))letshrink_to_fitv:unit=ifv.size=0thenv.vec<-[||]elseifv.size<Array.lengthv.vecthenv.vec<-Array.subv.vec0v.sizeletsort'cmpv=(* possibly copy array (to avoid junk at its end), then sort the array *)leta=ifArray.lengthv.vec=v.sizethenv.vecelseArray.subv.vec0v.sizeinArray.fast_sortcmpa;v.vec<-aletsortcmpv=letv'={size=v.size;vec=Array.subv.vec0v.size}inArray.sortcmpv'.vec;v'letuniq_sortcmpv=sort'cmpv;letn=v.sizein(* traverse to remove duplicates. i= current index,
j=current append index, j<=i. new_size is the size
the vector will have after removing duplicates. *)letrectraverseprevij=ifi>=nthen()(* done traversing *)elseifcmpprevv.vec.(i)=0then(v.size<-v.size-1;traverseprev(i+1)j(* duplicate, remove it *))else(v.vec.(j)<-v.vec.(i);traversev.vec.(i)(i+1)(j+1))(* keep it *)inifv.size>0thentraversev.vec.(0)11(* start at 1, to get the first element in hand *)letiterkv=let{vec;size=n}=vinfori=0ton-1dok(Array.unsafe_getveci)doneletiterikv=let{vec;size=n}=vinfori=0ton-1doki(Array.unsafe_getveci)doneletmapfv=ifarray_is_empty_vthencreate()else(let{vec;size}=vinletvec=Array.initsize(funi->f(Array.unsafe_getveci))in{size;vec})letmapifv=ifarray_is_empty_vthencreate()else(let{vec;size}=vinletvec=Array.initsize(funi->fi(Array.unsafe_getveci))in{size;vec})letmap_in_placefv=let{vec;size=n}=vinfori=0ton-1doArray.unsafe_setveci(f(Array.unsafe_getveci))doneletfilter_in_placepv=leti=ref0in(* cur element *)letj=ref0in(* cur insertion point *)letn=v.sizeinwhile!i<ndoifpv.vec.(!i)then((* move element i at the first empty slot.
invariant: i >= j*)if!i>!jthenv.vec.(!j)<-v.vec.(!i);incri;incrj)elseincridone;(* free elements *)fill_with_junk_v.vec!j(v.size-!j);v.size<-!jletfilterpv=ifarray_is_empty_vthencreate()else(letv'=create_with~capacity:v.sizev.vec.(0)initer(funx->ifpxthenpush_unsafe_v'x)v;v')letfoldfaccv=let{vec;size}=vinletrecfoldacci=ifi=sizethenaccelse(letx=Array.unsafe_getveciinfold(faccx)(i+1))infoldacc0letfoldifaccv=let{vec;size}=vinletrecfoldacci=ifi=sizethenaccelse(letx=Array.unsafe_getveciinfold(fiaccx)(i+1))infoldacc0letexistspv=letn=v.sizeinletrecchecki=ifi=nthenfalseelsepv.vec.(i)||check(i+1)incheck0letfor_allpv=letn=v.sizeinletrecchecki=ifi=nthentrueelsepv.vec.(i)&&check(i+1)incheck0letmember~eqxv=exists(eqx)vletfind_internal_pv=letn=v.sizeinletrecchecki=ifi=nthenraise_notraceNot_foundelse(letx=v.vec.(i)inifpxthenxelsecheck(i+1))incheck0letfind_exnpv=tryfind_internal_pvwithNot_found->raiseNot_foundletfindpv=trySome(find_internal_pv)withNot_found->Noneletfind_mapfv=letn=v.sizeinletrecsearchi=ifi=nthenNoneelse(matchfv.vec.(i)with|None->search(i+1)|Some_asres->res)insearch0letfilter_mapfv=letv'=create()initer(funx->matchfxwith|None->()|Somey->pushv'y)v;v'letfilter_map_in_placefv=leti=ref0in(* cur element *)letj=ref0in(* cur insertion point *)letn=v.sizeinwhile!i<ndomatchfv.vec.(!i)with|None->incri(* drop *)|Somey->(* move element i at the first empty slot.
invariant: i >= j*)v.vec.(!j)<-y;incri;incrjdone;(* free elements *)fill_with_junk_v.vec!j(v.size-!j);v.size<-!jletflat_mapfv=letv'=create()initer(funx->iter(pushv')(fx))v;v'letflat_map_seqfv=letv'=create()initer(funx->letseq=fxinappend_seqv'seq)v;v'letflat_map_listfv=letv'=create()initer(funx->letl=fxinappend_listv'l)v;v'letmonoid_productfa1a2:_t=letna1=a1.sizeininit(na1*a2.size)(funi_prod->leti=i_prodmodna1inletj=i_prod/na1infa1.vec.(i)a2.vec.(j))let(>>=)xf=flat_mapfxlet(>|=)xf=mapfxletrev_in_placev=ifv.size>0then(letn=v.sizeinletvec=v.vecinfori=0to(n-1)/2doletx=Array.unsafe_getveciinlety=Array.unsafe_getvec(n-i-1)inArray.unsafe_setveciy;Array.unsafe_setvec(n-i-1)xdone)letrevv=letv'=copyvinrev_in_placev';v'letrev_iterfv=let{vec;size=n}=vinfori=n-1downto0dof(Array.unsafe_getveci)doneletsizev=v.sizeletlengthv=v.sizeletcapacityv=Array.lengthv.vecletunsafe_get_arrayv=v.vecletof_iter?(init=create())seq=append_iterinitseq;initletof_seq?(init=create())seq=append_seqinitseq;initletto_itervk=iterkvletto_iter_revvk=let{vec;size=n}=vinfori=n-1downto0dok(Array.unsafe_getveci)doneletto_seqv=let{size;vec}=vinletrecauxi()=ifi>=sizethenSeq.NilelseSeq.Cons(vec.(i),aux(i+1))inaux0letto_seq_revv=let{size;vec}=vinletrecauxi()=ifi<0thenSeq.NilelseSeq.Cons(vec.(i),aux(i-1))inaux(size-1)letslice_itervstartlen=assert(start>=0&&len>=0);funk->let{size;vec}=vinassert(start+len<=size);fori=starttostart+len-1doletx=Array.unsafe_getveciinkxdoneletslicev=v.vec,0,v.sizelet(--)ij=ifi>jtheninit(i-j+1)(funk->i-k)elseinit(j-i+1)(funk->i+k)let(--^)ij=ifi=jthencreate()elseifi>jtheninit(i-j)(funk->i-k)elseinit(j-i)(funk->i+k)letof_arraya=ifArray.lengtha=0thencreate()else{size=Array.lengtha;vec=Array.copya}letof_listl=matchlwith|[]->create()|[x]->returnx|[x;y]->{size=2;vec=[|x;y|]}|x::_->letv=create_with~capacity:(List.lengthl)xinList.iter(push_unsafe_v)l;vletto_arrayv=Array.subv.vec0v.sizeletto_listv=List.rev(fold(funaccx->x::acc)[]v)letof_gen?(init=create())g=letrecauxg=matchg()with|None->init|Somex->pushinitx;auxginauxgletto_genv=let{size;vec}=vinleti=ref0infun()->if!i<sizethen(letx=vec.(!i)inincri;Somex)elseNoneletto_string?(start="")?(stop="")?(sep=", ")item_to_stringv=start^(to_listv|>List.mapitem_to_string|>String.concatsep)^stopletpp?(pp_start=fun_()->())?(pp_stop=fun_()->())?(pp_sep=funfmt()->Format.fprintffmt",@ ")pp_itemfmtv=pp_startfmt();iteri(funix->ifi>0thenpp_sepfmt();pp_itemfmtx)v;pp_stopfmt()let(let+)=(>|=)let(let*)=(>>=)let[@inline](and+)a1a2=monoid_product(funxy->x,y)a1a2let(and*)=(and+)