123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185openBuf(* Move-to-front codec *)moduleMtf_table:sigtype'atvalcreate:unit->'attypeindex=intvalnot_found:indexvalencode:'at->if_absent:(unit->'a)->string->index*'avaldecode:'at->if_absent:(unit->string*'a)->index->string*'avallast:'at->'aoptionend=structtype'aentry=Empty|Fullofstring*'atype'at='aentryarrayletlength=31letcreate()=Array.makelengthEmptytypeindex=intletnot_found=lengthletswapmtfi=assert(i<>not_found);lete=matchmtf.(i)with|Empty->assertfalse|Full_ase->einArray.blitmtf0mtf1i;mtf.(0)<-eletpushmtfkv=Array.blitmtf0mtf1(length-1);mtf.(0)<-Full(k,v)letencodemtf~if_absentx=letrecgomtfxi=ifi=lengththenletv=if_absent()inpushmtfxv;not_found,velsematchmtf.(i)with|Empty->letv=if_absent()inpushmtfxv;not_found,v|Full(k,v)whenString.equalkx->swapmtfi;i,v|Full_->gomtfx(i+1)ingomtfx0letdecodemtf~if_absenti=ifi=not_foundthenbeginlet(k,v)askv=if_absent()inpushmtfkv;kvendelsebeginswapmtfi;matchmtf.(0)with|Empty->assertfalse|Full(k,v)->k,vendletlastmtf=matchmtf.(length-1)with|Empty->None|Full(_,v)->Somevend(** Source locations *)moduleLocation=structtypet={filename:string;line:int;start_char:int;end_char:int;defname:string;}letto_string{filename;line;start_char;end_char;defname}=Printf.sprintf"%s@%s:%d:%d-%d"defnamefilenamelinestart_charend_charletunknown={filename="<unknown>";line=1;start_char=1;end_char=1;defname="??"}endtypestate=unitMtf_table.tMtf_table.tmoduleWriter=structopenBuf.Writetypet=stateletcreate()=Mtf_table.create()letmax_length=4*1024letput_location(file_mtf:t)b(id,locs)=lettotal_size_max=(* Worst-case size, assuming no MTF hits *)List.fold_left(funsz(loc:Location.t)->sz+6+(String.lengthloc.filename+1)+(String.lengthloc.defname+1))(8+1)locsinletno_truncation=List.lengthlocs<=255&&total_size_max<=max_lengthinletlocs=ifno_truncationthenlocselse[Location.unknown]inletstart_pos=b.Write.posinput_64b(Int64.of_intid);put_8b(List.lengthlocs);locs|>List.iter(fun(loc:Location.t)->letclampnlim=ifn<0||n>limthenlimelseninletline_number=clamploc.line0xfffffinletstart_char=clamploc.start_char0xfffinletend_char=clamploc.end_char0xfffinletfilename_code,defn_mtf=Mtf_table.encodefile_mtf~if_absent:Mtf_table.createloc.filenameinletdefname_code,()=Mtf_table.encodedefn_mtf~if_absent:(fun()->())loc.defnameinletencoded=Int64.(logor(of_intline_number)(logor(shift_left(of_intstart_char)20)(logor(shift_left(of_intend_char)(20+8))(logor(shift_left(of_int(filename_code:>int))(20+8+10))(shift_left(of_int(defname_code:>int))(20+8+10+5))))))input_32b(Int64.to_int32encoded);put_16b(Int64.(to_int(shift_rightencoded32)));iffilename_code=Mtf_table.not_foundthenput_stringbloc.filename;ifdefname_code=Mtf_table.not_foundthenput_stringbloc.defname);ifno_truncationthenassert(b.pos-start_pos<=total_size_max)endmoduleReader=structopenBuf.Readtypet=stateletcreate()=Mtf_table.create()letget_location(file_mtf:t)b=letid=Int64.to_int(get_64b)inletnlocs=get_8binletlocs=List.initnlocs(fun_->letlow=get_32binlethigh=get_16binletencoded=Int64.(logor(shift_left(of_inthigh)32)(logand(of_int32low)0xffffffffL))inletline,start_char,end_char,filename_code,defname_code=Int64.(to_int(logand0xfffffLencoded),to_int(logand0xffL(shift_rightencoded20)),to_int(logand0x3ffL(shift_rightencoded(20+8))),to_int(logand0x1fL(shift_rightencoded(20+8+10))),to_int(logand0x1fL(shift_rightencoded(20+8+10+5))))inletfilename,defn_mtf=Mtf_table.decodefile_mtf~if_absent:(fun()->lets=get_stringbin(* Reuse the defname MTF table that's about to be pushed off.
This is only present to match a bug in the v001 encoder,
which sometimes generated traces relying on this behaviour.
The current encoder never relies on this, so once v001
trace files stop mattering, this match can be deleted *)letd=matchMtf_table.lastfile_mtfwith|Somev->v|None->Mtf_table.create()ins,d)filename_codeinletdefname,()=Mtf_table.decodedefn_mtf~if_absent:(fun()->lets=get_stringbins,())defname_codein{Location.line;start_char;end_char;filename;defname;})in(id,locs)end