Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file batDeque.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311(*
* Deque -- functional double-ended queues
* Copyright (C) 2011 Batteries Included Development Team
*
* 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
*)type'adq={front:'alist;flen:int;rear:'alist;rlen:int}letinvariants t=assert(List.lengtht.front=t.flen);assert(List.lengtht.rear=t.rlen)type'at='adqtype'aenumerable='attype'amappable='atletempty={front=[];flen =0;rear=[];rlen=0}letsizeq=q.flen+q.rlenletconsxq={qwithfront=x::q.front;flen=q.flen+1}(*$T cons
size (cons 1 empty) = 1
to_list(cons 1 empty) <> to_list(cons 2 empty)
*)(*$Q cons
(Q.list Q.pos_int) ~count:10 \
(fun l -> List.fold_left (fun q x -> cons x q) empty l |> to_list = List.rev l)
*)letsnocqx={qwithrear=x::q.rear;rlen=q.rlen+1}(*$T cons; snoc to_list(cons 1 empty) = to_list(snoc empty 1)
to_list(cons 1 (cons 2 empty)) = (to_list (snoc (snoc empty 2) 1) |> List.rev)
*)(*$Q snoc
(Q.list Q.int) (fun l -> List.fold_left snoc empty l |> to_list = l)
*)letfrontq=matchqwith|{front=h::front;flen=flen;_}->Some(h,{qwithfront=front;flen=flen-1})|{rear=[];_}->None|{rear=rear;rlen=rlen;_}->(* beware: when rlen = 1, we must put the only element of
* the deque at the front (ie new_flen = 1, new_rlen = 0) *)letnew_flen=(rlen+1)/2inletnew_rlen=rlen/2in(* we splitthe non empty list in half because if we transfer
* everything to the front, then a call to rear would also
* transfer everything to the rear etc. -> no amortization
* (but we could transfer 3/4 instead of 1/2 of the list for instance) *)letrear,rev_front=BatList.split_atnew_rlenrearinletfront=List.revrev_frontinSome(List.hdfront,{front=List.tlfront ;flen=new_flen-1;rear=rear;rlen=new_rlen})(*$T front
front(cons 1 empty) = Some(1,empty)
front(snoc empty 1) = Some(1,empty)
*)letrearq=matchqwith|{rear=t::rear;rlen=rlen;_}->Some({qwithrear=rear;rlen=rlen-1},t)|{front=[];_}->None|{front=front;flen=flen;_}->letnew_rlen=(flen+1)/2inletnew_flen=flen/2inletfront,rev_rear=BatList.split_atnew_flenfrontinletrear=List.revrev_rearinSome({front=front;flen=new_flen;rear=List.tlrear;rlen=new_rlen-1},List.hdrear)(*$T rear
match rear(empty |> cons 1 |> cons 2) with | Some(_, 1) -> true | _ -> false
*)leteq?(eq=(=))q1q2=(* lexicographic comparison of the lists
(front1 @ rev rear1) and (front2 @ rev rear2). If front1 is a prefix of
front2, then (rev rear1) is used to continue.
Reversing rear lists is only used if front lists are equal. *)letreceq_lexicofront1rear1front2rear2 =matchfront1,front2with|[],[]->beginmatchrear1,rear2with|[],[]-> true|_::_,_::_->eq_lexicorear1[]rear2[]|_->falseend|_::_,[]->beginmatchrear2with|[]->false|_::_->eq_lexicofront1rear1(List.revrear2)[]end|[],_::_->beginmatchrear1with|[]->false|_::_->eq_lexico(List.revrear1)[]front2rear2end|x1::front1',x2::front2'->eqx1x2&&eq_lexicofront1'rear1front2'rear2inq1.flen+q1.rlen =q2.flen +q2.rlen &&eq_lexicoq1.frontq1.rearq2.front q2.rearletrevq={front =q.rear;flen=q.rlen;rear=q.front;rlen=q.flen}(*$Q rev
(Q.list Q.pos_int) (fun l -> let q = of_list l in rev q |> to_list = List.rev l)
*)(*$T eq
eq (empty |> cons 1 |> cons 2 |> cons 3) (rev (empty |> cons 3 |> cons 2 |> cons 1))
not (eq (empty |> cons 1 |> cons 2) (empty |> cons 2 |> cons 1))
*)letof_listl={front=l;flen=List.lengthl;rear=[];rlen=0}(*$Q eq
(Q.list Q.pos_int) ~count:20 (fun l -> eq (of_list l) (rev (of_list (List.rev l))))
*)letis_emptyq=sizeq=0letappend qr=ifsizeq>sizerthen{qwithrlen=q.rlen+sizer;rear=BatList.appendr.rear(List.rev_appendr.frontq.rear)}else{rwithflen=r.flen+sizeq;front=BatList.appendq.front(List.rev_append q.rearr.front)}letappend_listql=letn=List.lengthlin{qwithrear =List.rev_appendlq.rear;rlen=q.rlen+n}letprepend_listlq=letn=List.lengthlin{qwithfront =BatList.appendlq.front;flen=q.flen+n}letrotate_forwardq=matchfrontqwith|Some(h,d)->snocdh|None->q(*$T rotate_forward to_list (rotate_forward empty) = []
to_list (rotate_forward (of_list [1; 2; 3])) = [2; 3; 1]
*)letrotate_backwardq=matchrearqwith|Some(t,d)->consdt|None->q(*$T rotate_backward
to_list (rotate_backward empty) = []
to_list (rotate_backward (of_list [1; 2; 3])) = [3; 1; 2]
*)letat?(backwards=false)qn=letsize_front=q.fleninletsize_rear =q.rleninifn<0||n>=size_rear+size_frontthenNoneelseSome(ifbackwardsthenifn<size_rear thenBatList.atq.rear nelseBatList.atq.front(size_front-1-(n-size_rear))elseifn<size_frontthenBatList.atq.frontnelseBatList.atq.rear(size_rear-1-(n-size_front)))letmapfq=letrecgoqr=matchfrontqwith|None->r|Some(x,q)->goq(snocr(fx))ingoqemptyletmapifq=letrecgonqr=matchfrontqwith|None->r|Some(x,q)->go(n+1)q(snocr(fnx))ingo0qemptyletiterfq=letrecgoq=matchfrontqwith|None->()|Some(x,q)->fx;goqingoqletiterifq=letrecgonq=matchfrontqwith|None->()|Some(x,q)->fnx;go(n+1)qingo0qletrecfold_leftfnaccq=matchfrontqwith|None->acc|Some(f,q)->fold_left fn(fnaccf)qletrecfold_rightfnqacc=matchrearqwith|None->acc|Some(q,r)->fold_right fnq(fnracc)letto_listq=BatList.appendq.front(BatList.revq.rear)letfind?(backwards=false)test q=letrecspinkfr=matchfwith|[]->beginmatchrwith|[]->None|_->spink(List.revr)[]end|x::f->iftestxthenSome(k,x)elsespin(k+1)frinifbackwardsthenspin0q.rearq.frontelsespin0q.frontq.rearletrecenumq=letcur=refqinletnext()=matchfront!curwith|None->raise BatEnum.No_more_elements|Some(x,q)->cur:=q;xinletcount()=size!curinletclone()=enum !curinBatEnum.make~next ~count~cloneletof_enume=BatEnum.foldsnocemptye(*$Q enum
(Q.list Q.int) (fun l -> List.of_enum (enum (List.fold_left snoc empty l)) = l)
*)(*$Q of_enum
(Q.list Q.int) (fun l -> to_list (of_enum (List.enum l)) = l)
*)letprint?(first="[")?(last="]")?(sep="; ")eleproutdq=letrecspindq=matchfrontdqwith|None->()|Some(a,dq)whensizedq=0->eleprouta|Some(a,dq)->eleprouta;BatInnerIO.nwriteoutsep;spindqinBatInnerIO.nwriteoutfirst;spindq;BatInnerIO.nwriteoutlast(*$Q print (Q.list Q.int) (fun l -> \
BatIO.to_string (print ~first:"<" ~last:">" ~sep:"," Int.print) (of_list l) \
= BatIO.to_string (List.print ~first:"<" ~last:">" ~sep:"," Int.print) l)
*)