123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149(* Doubly-linked nodes carrying integer tags drawn from [0, universe]. The tags
are kept strictly increasing along the list, so [compare] is a tag
comparison. Insertion picks the midpoint tag between neighbours; when two
neighbours are adjacent there is no midpoint, so the whole list is relabelled
with evenly-spaced tags and the insertion retried. With a 2^62 universe the
gaps are large, so relabels are rare in practice. *)(* Well within [max_int] (2^62 - 1 on 64-bit OCaml) so midpoints and the
relabel's [i * step] never overflow; 2^60 still leaves ~2.9e15 of gap for a
few hundred entries. *)letuniverse=1lsl60type'anode={data:'a;id:int;(** stable identity, unlike [tag] which a relabel reassigns *)mutabletag:int;mutableprev:'anodeoption;mutablenext:'anodeoption;mutablelive:bool;}type'at={mutablehead:'anodeoption;mutabletail:'anodeoption;mutablecount:int;mutablenext_id:int;}letv()={head=None;tail=None;count=0;next_id=0}letfresh_idt=letid=t.next_idint.next_id<-id+1;idletis_emptyt=t.count=0letlengtht=t.countletdatan=n.dataletis_liven=n.liveletrelabelt=letstep=universe/(t.count+1)inletrecloopi=function|None->()|Somen->n.tag<-i*step;loop(i+1)n.nextinloop1t.headletrecinsert_aftertnx=ifnotn.livetheninvalid_arg"Order_maintenance.insert_after: stale node";letsucc=n.nextinletlo=n.taginlethi=matchsuccwithSomes->s.tag|None->universeinifhi-lo<=1then(relabelt;insert_aftertnx)elseletnode={data=x;id=fresh_idt;tag=lo+((hi-lo)/2);prev=Somen;next=succ;live=true;}inn.next<-Somenode;(matchsuccwith|Somes->s.prev<-Somenode|None->t.tail<-Somenode);t.count<-t.count+1;nodeletrecinsert_beforetnx=ifnotn.livetheninvalid_arg"Order_maintenance.insert_before: stale node";matchn.prevwith|Somep->insert_aftertpx|None->(* [n] is the head: pick a tag between 0 and [n]'s tag. *)letlo=0andhi=n.taginifhi-lo<=1then(relabelt;insert_beforetnx)elseletnode={data=x;id=fresh_idt;tag=lo+((hi-lo)/2);prev=None;next=Somen;live=true;}inn.prev<-Somenode;t.head<-Somenode;t.count<-t.count+1;nodeletadd_lasttx=matcht.tailwith|Sometail->insert_afterttailx|None->letnode={data=x;id=fresh_idt;tag=universe/2;prev=None;next=None;live=true;}int.head<-Somenode;t.tail<-Somenode;t.count<-1;nodeletremovetn=ifnotn.livetheninvalid_arg"Order_maintenance.remove: stale node";(matchn.prevwithSomep->p.next<-n.next|None->t.head<-n.next);(matchn.nextwithSomes->s.prev<-n.prev|None->t.tail<-n.prev);n.live<-false;n.prev<-None;n.next<-None;t.count<-t.count-1letcompareab=Int.comparea.tagb.tagletto_listt=letrecloopacc=function|None->List.revacc|Somen->loop(n.data::acc)n.nextinloop[]t.headletnodest=letrecloopacc=function|None->List.revacc|Somen->loop(n::acc)n.nextinloop[]t.headletnextn=n.nextletprevn=n.prevletidn=n.id