Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file ranges.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133(*
* Copyright (c) 2022-2023 Tarides <contact@tarides.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)open!Importtyperange={off:int63;len:int63}moduleStack=structtypet=Empty|Stackof{mutablelen:int;arr:int63array;prev:t}letcapacity=131_072(* = 128*1024, a large but not too large chunk size *)letmakeprev=Stack{len=0;arr=Array.makecapacityInt63.zero;prev}letis_full=functionEmpty->true|Stacks->s.len>=capacityletrecpushxt=matchtwith|Stackswhennot(is_fullt)->leti=s.lenins.len<-i+2;s.arr.(i)<-x.off;s.arr.(i+1)<-x.len;t|_->pushx(maket)letrecto_seqt()=matchtwith|Empty->Seq.Nil|Stack{len;arr;prev}->assert(lenmod2=0);letrecgoi()=ifi<0thento_seqprev()elseletrange={off=arr.(2*i);len=arr.((2*i)+1)}inSeq.Cons(range,go(i-1))ingo((len/2)-1)()endtypet={mutablelast:rangeoption;mutableranges:Stack.t;mutablecount:int;mutableout_of_order:rangelist;}letmake()={last=None;ranges=Stack.Empty;count=0;out_of_order=[]}letcountt=t.countletadd~off~lent=t.count<-t.count+1;letopenInt63.Syntaxinletlen=Int63.of_intleninmatcht.lastwith|None->t.last<-Some{off;len}|Somelastwhenoff+len=last.off->(* latest interval can be fused with the previous one *)t.last<-Some{off;len=len+last.len}|Somelastwhenoff+len<last.off->(* disjoint and strictly smaller *)t.last<-Some{off;len};t.ranges<-Stack.pushlastt.ranges|Some_->(* latest range is not strictly smaller than previous,
* this is only expected on legacy data with wrong object ordering
* and is handled as a special case. *)t.out_of_order<-{off;len}::t.out_of_orderletranges_to_seqt()=matcht.lastwith|None->Seq.Nil|Somerange->Seq.Cons(range,Stack.to_seqt.ranges)letout_of_order_to_seqt=List.to_seq@@List.sort_uniq(funab->Int63.comparea.offb.off)t.out_of_orderletrecseq_mergexsys()=match(xs(),ys())with|Seq.Nil,rest|rest,Seq.Nil->rest|Seq.Cons(x,xs'),Seq.Cons(y,ys')->(matchInt63.comparex.offy.offwith|0->assert(x.len=y.len);Seq.Cons(x,seq_mergexs'ys')|cwhenc<0->Seq.Cons(x,seq_mergexs'ys)|_->Seq.Cons(y,seq_mergexsys'))typefused=Disjointofrange*range|Overlapofrangeletfusefstsnd=letopenInt63.Syntaxinletfst_end=fst.off+fst.leninletsnd_end=snd.off+snd.leniniffst_end<snd.offthenDisjoint(fst,snd)elseifsnd_end<fst.offthenDisjoint(snd,fst)elseletstart=minfst.offsnd.offinletstop=maxfst_endsnd_endinOverlap{off=start;len=stop-start}letrecseq_fuse?prevs()=match(prev,s())with|None,Seq.Nil->Seq.Nil|Someprev,Nil->Seq.Cons(prev,Seq.empty)|None,Cons(x,xs)->seq_fuse~prev:xxs()|Someprev,Cons(x,xs)->(matchfusexprevwith|Disjoint(fst,snd)->Seq.Cons(fst,seq_fuse~prev:sndxs)|Overlapprev->seq_fuse~prevxs())letiterfnt=letin_order=ranges_to_seqtinletranges=matcht.out_of_orderwith|[]->in_order|_->seq_fuse(seq_mergein_order(out_of_order_to_seqt))inSeq.iter(fun{off;len}->fn~off~len)ranges