123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177open!ImportincludeStack_intfletraise_s=Error.raise_s(* This implementation is similar to [Deque] in that it uses an array of ['a] and
a mutable [int] to indicate what in the array is used. We choose to implement [Stack]
directly rather than on top of [Deque] for performance reasons. E.g. a simple
microbenchmark shows that push/pop is about 20% faster. *)type'at={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|{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])::bndsinPpx_sexp_conv_lib.Sexp.Listbnds[@@@end]letsexp_of_t_internal=sexp_of_tletsexp_of_t=`Rebound_laterlet_=sexp_of_tletcapacityt=Option_array.lengtht.eltsletinvariantinvariant_a({length;elts}ast):unit=tryassert(0<=length&&length<=Option_array.lengthelts);fori=0tolength-1doinvariant_a(Option_array.get_some_exneltsi)done;(* We maintain the invariant that unused elements are unset to avoid a space
leak. *)fori=lengthtoOption_array.lengthelts-1doassert(not(Option_array.is_someeltsi))donewith|exn->raise_s(Sexp.message"Stack.invariant failed"["exn",exn|>Exn.sexp_of_t;"stack",t|>sexp_of_t_internalsexp_of_opaque]);;letcreate(typea)():at={length=0;elts=Option_array.empty}letlengtht=t.lengthletis_emptyt=lengtht=0(* The order in which elements are visited has been chosen so as to be backwards
compatible with both [Linked_stack] and [Caml.Stack] *)letfoldt~init~f=letr=refinitinfori=t.length-1downto0dor:=f!r(Option_array.get_some_exnt.eltsi)done;!r;;letitert~f=fori=t.length-1downto0dof(Option_array.get_some_exnt.eltsi)done;;moduleC=Container.Make(structtypenonrec'at='atletfold=foldletiter=`Customiterletlength=`Customlengthend)letmem=C.memletexists=C.existsletfor_all=C.for_allletcount=C.countletsum=C.sumletfind=C.findletfind_map=C.find_mapletto_list=C.to_listletto_array=C.to_arrayletmin_elt=C.min_eltletmax_elt=C.max_eltletfold_result=C.fold_resultletfold_until=C.fold_untilletof_list(typea)(l:alist)=ifList.is_emptylthencreate()else(letlength=List.lengthlinletelts=Option_array.create~len:(2*length)inletr=reflinfori=length-1downto0domatch!rwith|[]->assertfalse|a::l->Option_array.set_someeltsia;r:=ldone;{length;elts});;letsexp_of_tsexp_of_at=List.sexp_of_tsexp_of_a(to_listt)lett_of_sexpa_of_sexpsexp=of_list(List.t_of_sexpa_of_sexpsexp)letresizetsize=letarr=Option_array.create~len:sizeinOption_array.blit~src:t.elts~dst:arr~src_pos:0~dst_pos:0~len:t.length;t.elts<-arr;;letset_capacitytnew_capacity=letnew_capacity=maxnew_capacity(lengtht)inifnew_capacity<>capacitytthenresizetnew_capacity;;letpushta=ift.length=Option_array.lengtht.eltsthenresizet(2*(t.length+1));Option_array.set_somet.eltst.lengtha;t.length<-t.length+1;;letpop_nonemptyt=leti=t.length-1inletresult=Option_array.get_some_exnt.eltsiinOption_array.set_nonet.eltsi;t.length<-i;result;;letpop_error=Error.of_string"Stack.pop of empty stack"letpopt=ifis_emptytthenNoneelseSome(pop_nonemptyt)letpop_exnt=ifis_emptytthenError.raisepop_errorelsepop_nonemptytlettop_nonemptyt=Option_array.get_some_exnt.elts(t.length-1)lettop_error=Error.of_string"Stack.top of empty stack"lettopt=ifis_emptytthenNoneelseSome(top_nonemptyt)lettop_exnt=ifis_emptytthenError.raisetop_errorelsetop_nonemptytletcopy{length;elts}={length;elts=Option_array.copyelts}letcleart=ift.length>0then(fori=0tot.length-1doOption_array.set_nonet.eltsidone;t.length<-0);;letuntil_emptytf=letrecloop()=ift.length>0then(f(pop_nonemptyt);loop())inloop();;letsingletonx=lett=create()inpushtx;t;;