123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383(*
* Dllist- a mutable, circular, doubly linked list library
* Copyright (C) 2004 Brian Hurt, Jesse Guardiani
* 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
*)type'anode_t={mutabledata:'a;mutablenext:'anode_t;mutableprev:'anode_t}type'aenum_t={mutablecurr:'anode_t;mutablevalid:bool}type'at='anode_ttype'amappable='attype'aenumerable='atexceptionEmptyletinvariantst=assert(t.next.prev ==t&&t.prev.next==t);letcurrent=reft.nextinwhile !current!=tdolett=!current inassert(t.next.prev==t&&t.prev.next==t);current:=t.nextdoneletcreatex=letrecnn={data=x;next=nn;prev=nn}innnletlengthnode=let recloopcntn=ifn==nodethencntelseloop(cnt +1)n.nextinloop1node.nextletaddnodeelem =letnn={data =elem;next=node.next;prev =node}innode.next.prev<-nn;node.next<-nn(*$T add
let t = of_list [1;2;3] in add t 12; invariants t; to_list t = [1;12;2;3]
let t = of_list [1] in add t 2; invariants t; to_list t = [1;2]
*)letappendnodeelem=letnn={data =elem;next=node.next;prev =node}innode.next.prev<-nn;node.next<-nn;nnletprependnodeelem=letnn={data =elem;next=node;prev=node.prev}innode.prev.next<-nn;node.prev<-nn;nnletpromotenode=letnext=node.nextinletprev=node.previnifnext!=prev thenbeginnext.next.prev<-node;node.next<-next.next;node.prev<-next;next.next<-node;next.prev<-prev;prev.next<-nextend(*$T promote
let t = of_list [1;2;3;4] in promote t; invariants t; to_list t = [1;3;4;2]
let t = of_list [1] in promote t; invariants t; to_list t = [1]
*)letdemotenode=letnext=node.nextinletprev=node.previnifnext!=prev thenbeginprev.prev.next<-node;node.prev<-prev.prev;node.next<-prev;prev.prev<-node;prev.next<-next;next.prev<-prevend(*$T demote
let t = of_list [1;2;3;4] in demote t; invariants t; to_list t = [1;4;2;3]
let t = of_list [1] in demote t; invariants t; to_list t = [1]
*)letremovenode=letnext=node.nextinifnext==node thenraiseEmpty;(* singleton list points to itself for next *)letprev=node.previn(* Remove node from list by linking prev and next together *)prev.next<-next;next.prev<-prev;(* Make node a singleton list by setting its next and prev to itself *)node.next<-node;node.prev<-node(*$T remove
let t = of_list [1;2;3;4] in let u = next t in remove t; invariants u; to_list u = [2;3;4]
let t = of_list [1;2] in let u = next t in remove t; invariants u; to_list u = [2]
let t = of_list [1;2] in let u = next t in remove t; try remove u; false with Empty -> true
let t = of_list [1] in try remove t; false with Empty -> true
*)letdropnode=letnext=node.next inifnext==node thenraiseEmpty;(* singleton list points to itself for next *)letprev=node.previnprev.next<-next;next.prev<-prev;node.next<-node;node.prev<-node;next(*$T drop
let t = of_list [1;2;3;4] in let t = drop t in invariants t; to_list t = [2;3;4]
let t = of_list [1] in try ignore (drop t); false with Empty -> true
*)letrev_dropnode=letnext=node.nextinifnext==node thenraiseEmpty;(* singleton list points to itself for next *)letprev=node.previnprev.next<-next;next.prev<-prev;node.next<-node;node.prev<-node;prev(*$T rev_drop
let t = of_list [1;2;3;4] in let t = rev_drop t in invariants t; to_list t = [4;2;3]
let t = of_list [1] in try ignore (rev_drop t); false with Empty -> true
*)letsplicenode1node2=letnext =node1.next inletprev=node2.previnnode1.next<-node2;node2.prev<-node1;next.prev<-prev;prev.next<-nextletsetnodedata=node.data<-dataletgetnode=node.dataletnextnode=node.nextletprevnode=node.prevletskipnodeidx=letf=ifidx>0thennextelseprevinletrecloopidxn=ifidx==0thennelseloop(idx-1)(fn)inloop (absidx)nodeletrevnode=letrecloopnextn=beginletprev=n.previnn.next <-prev;n.prev<-next;ifn!=nodethenloopnprevendinloopnodenode.prev(*$T rev
let t = of_list [1] in rev t; invariants t; to_list t = [1]
let t = of_list [1;2;3;4] in rev t; invariants t; to_list t = [1;4;3;2]
*)letiterfnode=let()=fnode.datainletrecloopn=ifn!=nodethenlet()=fn.datainloopn.nextinloopnode.nextletfor_allpnode =letrecloopn=ifn==nodethentrueelsepn.data&&loopn.nextinpnode.data &&loopnode.nextletfindpnode=letrecloopn=ifn==nodethenraiseNot_foundelseifpn.datathennelseloopn.nextinifpnode.datathennodeelseloopnode.next(*$T find
find (fun x -> x mod 2 = 0) (of_list [1;3;4;5;7;6]) |> get = 4
find (fun x -> x = 1) (of_list [1;3;4;5;7;6]) |> get = 1
find (fun x -> x > 3) (of_list [-1;3;9;1;1;1]) |> get = 9
try find (fun x -> x land 3 = 2) (of_list [1;4;3])|>ignore; false with Not_found -> true
*)(*qtest TODO: migrate try into an exception test *)letexistspnode=letrecloopn=ifn==nodethenfalseelsepn.data||loopn.nextinpnode.data ||loopnode.nextletfold_left finitnode=letrecloopaccun=ifn==node thenaccuelseloop(faccun.data)n.nextinloop(finitnode.data)node.nextletfold_rightfnodeinit=letrecloopaccun=ifn==node thenfn.dataaccuelseloop(fn.dataaccu)n.previnloopinitnode.prevletmapfnode =letfirst=create(fnode.data)inletrecloop lastn=ifn==node thenbeginfirst.prev<-last;firstendelsebeginletnn={data=fn.data;next =first;prev=last}inlast.next<-nn;loop nnn.nextendinloopfirstnode.nextletcopynode=map(funx->x)nodeletto_listnode=fold_right (fundl->d::l)node[]letof_listlst=matchlstwith|[]->raiseEmpty|h::t->letfirst=createhinletreclooplast=function|[]->last.next<-first;first.prev<-last;first|h::t->letnn={data=h;next=first;prev=last}inlast.next<-nn;loop nntinloopfirstt(*$T
try ignore (of_list []); false with Empty -> true
*)letenumnode=letnexte()=ifnote.valid thenraiseBatEnum.No_more_elementselsebeginletrval=e.curr.dataine.curr<-e.curr.next;if(e.curr==node)thene.valid<-false;rvalendandcounte()=ifnote.valid then0elseletrecloopcntn=ifn==nodethencntelseloop(cnt+1)(n.next)inloop1(e.curr.next)inletrecclonee()=lete'={curr=e.curr;valid=e.valid}inBatEnum.make~next:(nexte')~count:(counte')~clone:(clonee')inlete={curr=node;valid=true}inBatEnum.make~next:(nexte)~count:(counte)~clone:(clonee)letrev_enumnode=letpreve()=ifnote.valid thenraiseBatEnum.No_more_elementselsebeginletrval=e.curr.dataine.curr<-e.curr.prev;if(e.curr==node)thene.valid<-false;rvalendandcounte()=ifnote.valid then0elseletrecloopcntn=ifn==nodethencntelseloop(cnt+1)(n.prev)inloop1(e.curr.prev)inletrecclonee()=lete'={curr=e.curr;valid=e.valid}inBatEnum.make~next:(preve')~count:(counte')~clone:(clonee')inlete={curr=node;valid=true}inBatEnum.make~next:(preve)~count:(counte)~clone:(clonee)letbackwardst=rev_enum(prevt)letof_enumenm=matchBatEnum.getenmwith|None->raiseEmpty|Some(d)->letfirst=createdinletfnd=appendndinignore(BatEnum.foldffirstenm);firstletprint?(first="[")?(last="]")?(sep="; ")print_aoutt=BatEnum.print~first ~last~sepprint_aout(enumt)letfilterfnode=(*TODO : makefaster*)of_enum(BatEnum.filterf(enumnode))letfilter_map fnode =(*TODO : makefaster*)of_enum(BatEnum.filter_mapf(enumnode))