Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file queue.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482open!Import(* [t] stores the [t.length] queue elements at consecutive increasing indices of [t.elts],
mod the capacity of [t], which is [Option_array.length t.elts]. The capacity is
required to be a power of two (user-requested capacities are rounded up to the nearest
power), so that mod can quickly be computed using [land t.mask], where [t.mask =
capacity t - 1]. So, queue element [i] is at [t.elts.( (t.front + i) land t.mask )].
[num_mutations] is used to detect modification during iteration. *)type'at={mutablenum_mutations:int;mutablefront:int;mutablemask:int;mutablelength:int;mutableelts:'aOption_array.t}[@@deriving_inlinesexp_of]letsexp_of_t:'a.('a->Ppx_sexp_conv_lib.Sexp.t)->'at->Ppx_sexp_conv_lib.Sexp.t=fun_of_a->function|{num_mutations=v_num_mutations;front=v_front;mask=v_mask;length=v_length;elts=v_elts}->letbnds=[]inletbnds=letarg=Option_array.sexp_of_t_of_av_eltsin(Ppx_sexp_conv_lib.Sexp.List[Ppx_sexp_conv_lib.Sexp.Atom"elts";arg])::bndsinletbnds=letarg=sexp_of_intv_lengthin(Ppx_sexp_conv_lib.Sexp.List[Ppx_sexp_conv_lib.Sexp.Atom"length";arg])::bndsinletbnds=letarg=sexp_of_intv_maskin(Ppx_sexp_conv_lib.Sexp.List[Ppx_sexp_conv_lib.Sexp.Atom"mask";arg])::bndsinletbnds=letarg=sexp_of_intv_frontin(Ppx_sexp_conv_lib.Sexp.List[Ppx_sexp_conv_lib.Sexp.Atom"front";arg])::bndsinletbnds=letarg=sexp_of_intv_num_mutationsin(Ppx_sexp_conv_lib.Sexp.List[Ppx_sexp_conv_lib.Sexp.Atom"num_mutations";arg])::bndsinPpx_sexp_conv_lib.Sexp.Listbnds[@@@end]moduletypeS=Queue_intf.Sletinc_num_mutationst=t.num_mutations<-t.num_mutations+1letcapacityt=t.mask+1letelts_indexti=(t.front+i)landt.maskletunsafe_getti=Option_array.unsafe_get_some_exnt.elts(elts_indexti)letunsafe_is_setti=Option_array.unsafe_is_somet.elts(elts_indexti)letunsafe_settia=Option_array.unsafe_set_somet.elts(elts_indexti)aletunsafe_unsetti=Option_array.unsafe_set_nonet.elts(elts_indexti)letcheck_index_exnti=ifi<0||i>=t.lengththenError.raise_s(Sexp.message"Queue index out of bounds"["index",i|>Int.sexp_of_t;"length",t.length|>Int.sexp_of_t]);;letgetti=check_index_exnti;unsafe_getti;;letsettia=check_index_exnti;inc_num_mutationst;unsafe_settia;;letis_emptyt=t.length=0letlength{length;_}=lengthletensure_no_mutationtnum_mutations=ift.num_mutations<>num_mutationsthenError.raise_s(Sexp.message"mutation of queue during iteration"["",t|>sexp_of_t(fun_->Sexp.Atom"_")]);;letcompare=letrecunsafe_compare_fromcompare_eltpos~t1~t2~len1~len2~mut1~mut2=matchpos=len1,pos=len2with|true,true->0|true,false->-1|false,true->1|false,false->letx=compare_elt(unsafe_gett1pos)(unsafe_gett2pos)inensure_no_mutationt1mut1;ensure_no_mutationt2mut2;(matchxwith|0->unsafe_compare_fromcompare_elt(pos+1)~t1~t2~len1~len2~mut1~mut2|n->n)infuncompare_eltt1t2->ifphys_equalt1t2then0elseunsafe_compare_fromcompare_elt0~t1~t2~len1:t1.length~len2:t2.length~mut1:t1.num_mutations~mut2:t2.num_mutations;;letequal=letrecunsafe_equal_fromequal_eltpos~t1~t2~mut1~mut2~len=pos=len||letb=equal_elt(unsafe_gett1pos)(unsafe_gett2pos)inensure_no_mutationt1mut1;ensure_no_mutationt2mut2;b&&unsafe_equal_fromequal_elt(pos+1)~t1~t2~mut1~mut2~leninfunequal_eltt1t2->phys_equalt1t2||letlen1=t1.lengthinletlen2=t2.lengthinlen1=len2&&unsafe_equal_fromequal_elt0~t1~t2~len:len1~mut1:t1.num_mutations~mut2:t2.num_mutations;;letinvariantinvariant_at=let{num_mutations;mask=_;elts;front;length}=tinassert(front>=0);assert(front<capacityt);letcapacity=capacitytinassert(capacity=Option_array.lengthelts);assert(capacity>=1);assert(Int.is_pow2capacity);assert(length>=0);assert(length<=capacity);fori=0tocapacity-1doifi<t.lengththen(invariant_a(unsafe_getti);ensure_no_mutationtnum_mutations)elseassert(not(unsafe_is_setti))done;;letcreate(typea)?capacity():at=letcapacity=matchcapacitywith|None->1|Somecapacity->ifcapacity<0thenError.raise_s(Sexp.message"cannot have queue with negative capacity"["capacity",capacity|>Int.sexp_of_t])elseifcapacity=0then1elseInt.ceil_pow2capacityin{num_mutations=0;front=0;mask=capacity-1;length=0;elts=Option_array.create~len:capacity};;letblit_to_array~srcdst=assert(src.length<=Option_array.lengthdst);letfront_len=Int.minsrc.length(capacitysrc-src.front)inletrest_len=src.length-front_leninOption_array.blit~len:front_len~src:src.elts~src_pos:src.front~dst~dst_pos:0;Option_array.blit~len:rest_len~src:src.elts~src_pos:0~dst~dst_pos:front_len;;letset_capacitytdesired_capacity=(* We allow arguments less than 1 to [set_capacity], but translate them to 1 to simplify
the code that relies on the array length being a power of 2. *)inc_num_mutationst;letnew_capacity=Int.ceil_pow2(max1(maxdesired_capacityt.length))inifnew_capacity<>capacitytthen(letdst=Option_array.create~len:new_capacityinblit_to_array~src:tdst;t.front<-0;t.mask<-new_capacity-1;t.elts<-dst);;letenqueueta=inc_num_mutationst;ift.length=capacitytthenset_capacityt(2*t.length);unsafe_settt.lengtha;t.length<-t.length+1;;letdequeue_nonemptyt=inc_num_mutationst;letelts=t.eltsinletfront=t.frontinletres=Option_array.get_some_exneltsfrontinOption_array.set_noneeltsfront;t.front<-elts_indext1;t.length<-t.length-1;res;;letdequeue_exnt=ifis_emptytthenraiseCaml.Queue.Emptyelsedequeue_nonemptytletdequeuet=ifis_emptytthenNoneelseSome(dequeue_nonemptyt)letfront_nonemptyt=Option_array.unsafe_get_some_exnt.eltst.frontletlast_nonemptyt=unsafe_gett(t.length-1)letpeekt=ifis_emptytthenNoneelseSome(front_nonemptyt)letpeek_exnt=ifis_emptytthenraiseCaml.Queue.Emptyelsefront_nonemptytletlastt=ifis_emptytthenNoneelseSome(last_nonemptyt)letlast_exnt=ifis_emptytthenraiseCaml.Queue.Emptyelselast_nonemptytletcleart=inc_num_mutationst;ift.length>0then(fori=0tot.length-1dounsafe_unsettidone;t.length<-0;t.front<-0);;letblit_transfer~src~dst?len()=inc_num_mutationssrc;inc_num_mutationsdst;letlen=matchlenwith|None->src.length|Somelen->iflen<0thenError.raise_s(Sexp.message"Queue.blit_transfer: negative length"["length",len|>Int.sexp_of_t]);minlensrc.lengthiniflen>0then(set_capacitydst(max(capacitydst)(dst.length+len));letdst_start=dst.front+dst.lengthinfori=0tolen-1do(* This is significantly faster than simply [enqueue dst (dequeue_nonempty src)] *)letsrc_i=(src.front+i)landsrc.maskinletdst_i=(dst_start+i)landdst.maskinOption_array.unsafe_set_somedst.eltsdst_i(Option_array.unsafe_get_some_exnsrc.eltssrc_i);Option_array.unsafe_set_nonesrc.eltssrc_idone;dst.length<-dst.length+len;src.front<-(src.front+len)landsrc.mask;src.length<-src.length-len);;letenqueue_alltl=(* Traversing the list up front to compute its length is probably (but not definitely)
better than doubling the underlying array size several times for large queues. *)set_capacityt(Int.max(capacityt)(t.length+List.lengthl));List.iterl~f:(funx->enqueuetx);;letfoldt~init~f=ift.length=0theninitelse(letnum_mutations=t.num_mutationsinletr=refinitinfori=0tot.length-1dor:=f!r(unsafe_getti);ensure_no_mutationtnum_mutationsdone;!r);;letfoldit~init~f=leti=ref0infoldt~init~f:(funacca->letacc=f!iaccaini:=!i+1;acc);;(* [iter] is implemented directly because implementing it in terms of [fold] is
slower. *)letitert~f=letnum_mutations=t.num_mutationsinfori=0tot.length-1dof(unsafe_getti);ensure_no_mutationtnum_mutationsdone;;letiterit~f=letnum_mutations=t.num_mutationsinfori=0tot.length-1dofi(unsafe_getti);ensure_no_mutationtnum_mutationsdone;;moduleC=Indexed_container.Make(structtypenonrec'at='atletfold=foldletiter=`Customiterletlength=`Customlengthletfoldi=`Customfoldiletiteri=`Customiteriend)letcount=C.countletexists=C.existsletfind=C.findletfind_map=C.find_mapletfold_result=C.fold_resultletfold_until=C.fold_untilletfor_all=C.for_allletmax_elt=C.max_eltletmem=C.memletmin_elt=C.min_eltletsum=C.sumletto_list=C.to_listletcounti=C.countiletexistsi=C.existsiletfind_mapi=C.find_mapiletfindi=C.findiletfor_alli=C.for_alli(* For [concat_map], [filter_map], and [filter], we don't create [t_result] with [t]'s
capacity because we have no idea how many elements [t_result] will ultimately hold. *)letconcat_mapt~f=lett_result=create()initert~f:(funa->List.iter(fa)~f:(funb->enqueuet_resultb));t_result;;letconcat_mapit~f=lett_result=create()initerit~f:(funia->List.iter(fia)~f:(funb->enqueuet_resultb));t_result;;letfilter_mapt~f=lett_result=create()initert~f:(funa->matchfawith|None->()|Someb->enqueuet_resultb);t_result;;letfilter_mapit~f=lett_result=create()initerit~f:(funia->matchfiawith|None->()|Someb->enqueuet_resultb);t_result;;letfiltert~f=lett_result=create()initert~f:(funa->iffathenenqueuet_resulta);t_result;;letfilterit~f=lett_result=create()initerit~f:(funia->iffiathenenqueuet_resulta);t_result;;letfilter_inplacet~f=lett2=filtert~fincleart;blit_transfer~src:t2~dst:t();;letfilteri_inplacet~f=lett2=filterit~fincleart;blit_transfer~src:t2~dst:t();;letcopysrc=letdst=create~capacity:src.length()inblit_to_array~srcdst.elts;dst.length<-src.length;dst;;letof_listl=(* Traversing the list up front to compute its length is probably (but not definitely)
better than doubling the underlying array size several times for large queues. *)lett=create~capacity:(List.lengthl)()inList.iterl~f:(funx->enqueuetx);t;;(* The queue [t] returned by [create] will have [t.length = 0], [t.front = 0], and
[capacity t = Int.ceil_pow2 len]. So, we only have to set [t.length] to [len] after
the blit to maintain all the invariants: [t.length] is equal to the number of elements
in the queue, [t.front] is the array index of the first element in the queue, and
[capacity t = Option_array.length t.elts]. *)letinitlen~f=iflen<0thenError.raise_s(Sexp.message"Queue.init: negative length"["length",len|>Int.sexp_of_t]);lett=create~capacity:len()inassert(Option_array.lengtht.elts>=len);fori=0tolen-1doOption_array.unsafe_set_somet.eltsi(fi)done;t.length<-len;t;;letof_arraya=init(Array.lengtha)~f:(Array.unsafe_geta)letto_arrayt=Array.initt.length~f:(funi->unsafe_getti)letmapta~f=letnum_mutations=ta.num_mutationsinlettb=create~capacity:ta.length()intb.length<-ta.length;fori=0tota.length-1doletb=f(unsafe_gettai)inensure_no_mutationtanum_mutations;Option_array.unsafe_set_sometb.eltsibdone;tb;;letmapit~f=leti=ref0inmapt~f:(funa->letresult=f!iaini:=!i+1;result);;letsingletonx=lett=create()inenqueuetx;t;;letsexp_of_tsexp_of_at=to_listt|>List.sexp_of_tsexp_of_alett_of_sexpa_of_sexpsexp=List.t_of_sexpa_of_sexpsexp|>of_list