123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2020 Nomadic Labs, <contact@nomadic-labs.com> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)type'anode={data:'a;mutableprev:'anodeoption;mutablenext:'anodeoption;}letdata{data;_}=datatype'att=|Emptyof{capacity:int}|Initedof{capacity:int;mutablesize:int;mutablefirst:'anode;mutablelast:'anode;}type'at='attrefletcreatecapacity=ifcapacity<=0thenraise(Invalid_argument"Ringo.Dll.create: negative or null capacity")elseref(Empty{capacity})letcapacitydll=match!dllwith|Empty{capacity}|Inited{capacity;_}->capacityletadd_and_return_eraseddlldata=match!dllwith|Empty{capacity}->letnode={data;prev=None;next=None}indll:=Inited{capacity;size=1;first=node;last=node;};(node,None)|Inited({capacity=1;size;first;last;}asdll)->assert(size=1);assert(first==last);assert(first.next=None);assert(first.prev=None);assert(last.next=None);assert(last.prev=None);letpops=lastinletnode={data;prev=None;next=None}indll.first<-node;dll.last<-node;(node,Somepops.data)|Inited({capacity;size;first;last;}asdll)->assert(first.prev=None);assert(last.next=None);ifsize<capacitythenbeginletnode={data;prev=None;next=Somefirst}infirst.prev<-Somenode;dll.first<-node;dll.size<-succdll.size;(node,None)endelsebeginletpops=lastin(matchlast.prevwith|Somenew_last->dll.last<-new_last;new_last.next<-None|None->(* This requires
(1) to have a single element,
(2) to have reached capacity, and
(3) to have a capacity > 1 *)assertfalse);pops.prev<-None;pops.next<-None;letnode={data;prev=None;next=Somedll.first}infirst.prev<-Somenode;dll.first<-node;(node,Somepops.data)endletadddlldata=fst@@add_and_return_eraseddlldataletadd_listdlll=letcapacity=capacitydllinletlength=List.lengthliniflength<capacitythenbeginList.map(adddll)l|>List.revendelsebeginList.fold_left(fun(index,acc)x->ifindex<length-capacitythen(index+1,acc)else(index+1,adddllx::acc))(0,[])l|>fun(_,acc)->List.revaccendletcleardll=match!dllwith|Empty_->()|Inited{capacity;_}->dll:=Empty{capacity}letrecfold_nodefaccnode=letacc=faccnodeinmatchnode.nextwith|None->acc|Somenext->fold_nodefaccnextletfolddll~init~f=match!dllwith|Empty_->init|Inited{first;_}->fold_nodefinitfirstletelementst=foldt~init:[]~f:(funaccelt->elt::acc)letelements_datat=foldt~init:[]~f:(funaccelt->elt.data::acc)letremovecnode=match!cwith|Empty_->assertfalse|Initeddll->beginmatch(node.prev,node.next)with|(None,None)->assert(node==dll.first);assert(node==dll.last);assert(dll.size=1);c:=Empty{capacity=dll.capacity}|(None,Somenext)->next.prev<-None;dll.first<-next;|(Someprev,None)->prev.next<-None;dll.last<-prev|(Someprev,Somenext)->prev.next<-node.next;next.prev<-node.prevend;node.prev<-None;node.next<-None;dll.size<-preddll.sizeletpromotedllnode=match!dllwith|Empty_->assertfalse|Initeddll->ifdll.first==nodethen()elsebeginletprev_first=dll.firstin(* first, promote neighbors *)beginmatch(node.prev,node.next)with|(None,None)->assertfalse|(None,Some_next)->assertfalse|(Someprev,None)->prev.next<-None;dll.last<-prev|(Someprev,Somenext)->prev.next<-node.next;next.prev<-node.prevend;(* promote node to first *)prev_first.prev<-Somenode;node.prev<-None;node.next<-Somedll.first;dll.first<-nodeend