123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162(* Variable-byte encoding of 8-byte integers (starting from 0). *)openPrintfopenBi_outbufopenBi_inbuftypeuint=int(* Maximum length of a vint decodable into an OCaml int,
maximum value of the highest byte of the largest vint supported *)letmax_vint_bytes,max_highest_byte=ifBi_util.int_sizemod7=0thenletm=Bi_util.int_size/7inleth=1lsl7-1inm,helseletm=Bi_util.int_size/7+1inleth=1lsl(Bi_util.int_sizemod7)-1inm,hletcheck_highest_bytex=ifx>max_highest_bytethenBi_util.error"Vint exceeding range of OCaml ints"letunsigned_of_signedi=ifi>=0then(*
0 -> 0
1 -> 2
2 -> 4
3 -> 6
*)ilsl1else(*
-1 -> 1
-2 -> 3
-3 -> 5
*)((-1-i)lsl1)lor1letsigned_of_unsignedi=ifiland1=0thenilsr1else-1-(ilsr1)letwrite_uvintbufi=Bi_outbuf.extendbufmax_vint_bytes;letx=refiinwhile!xlsr7<>0doletbyte=0x80lor(!xland0x7f)inBi_outbuf.unsafe_add_charbuf(Char.chrbyte);x:=!xlsr7;done;Bi_outbuf.unsafe_add_charbuf(Char.chr!x)letwrite_svintbufi=write_uvintbuf(unsigned_of_signedi)(* convenience *)letuvint_of_uint?bufi=letbuffer=matchbufwith|None->Bi_outbuf.create10|Someb->binBi_outbuf.clearbuffer;write_uvintbufferi;Bi_outbuf.contentsbufferletsvint_of_int?bufi=uvint_of_uint?buf(unsigned_of_signedi)letread_uvintib=letavail=Bi_inbuf.try_prereadibmax_vint_bytesinlets=ib.i_sinletpos=ib.i_posinletx=ref0in(tryfori=0toavail-1doletb=Char.code(Bytes.gets(pos+i))inx:=((bland0x7f)lsl(7*i))lor!x;ifb<0x80then(ib.i_pos<-pos+i+1;ifi+1=max_vint_bytesthencheck_highest_byteb;raiseExit)done;Bi_util.error"Unterminated vint or vint exceeding range of OCaml ints"withExit->());!xletread_svintib=signed_of_unsigned(read_uvintib)(* convenience *)letcheck_end_of_inputib=ifBi_inbuf.try_prereadib1>0thenBi_util.error"Junk input after end of vint"letuint_of_uvints=letib=Bi_inbuf.from_stringsinletx=read_uvintibincheck_end_of_inputib;xletint_of_svints=letib=Bi_inbuf.from_stringsinletx=read_svintibincheck_end_of_inputib;x(*
Testing
*)letstring_of_listl=letob=Bi_outbuf.create100inList.iter(write_uvintob)l;Bi_outbuf.contentsobletrecread_listib=ifib.i_pos<ib.i_lenthenletx=read_uvintibinx::read_listibelse[]letlist_of_strings=read_list(Bi_inbuf.from_strings)letprint_listl=List.iter(funi->printf"dec %i\nhex %x\nbin %s\n"ii(Bi_util.print_bits(Bi_util.string8_of_inti)))llettest()=letl=[0;0xfffffff;(0x01020304lsl32)lor0x05060708;max_int;min_int]inprintf"Input:\n";print_listl;letl'=list_of_string(string_of_listl)inprintf"Output:\n";print_listl';ifl=l'thenprint_endline"SUCCESS"elseprint_endline"FAILURE"