123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2021 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. *)(* *)(*****************************************************************************)typeerror+=Invalid_slotofintlet()=register_error_kind`Permanent~id:"slot.invalid_slot"~title:"invalid slot"~description:"Invalid slot"~pp:(funppfx->Format.fprintfppf"invalid slot: %d"x)Data_encoding.(obj1(req"bad_slot"int31))(functionInvalid_slotx->Somex|_->None)(funx->Invalid_slotx)includeCompare.Inttypeslot=t(* TODO? should there be some assertions to verify that slots are
never too big ? Or do that in a storage module that depends on
constants ? *)letencoding=Data_encoding.uint16letpp=Format.pp_print_intletzero=0letto_intx=x(* We assume 2^16 slots is big enough.
We could increase that, but we would need to make sure there is no big
performance penalty first. *)letmax_value=(1lsl16)-1letof_int_do_not_use_except_for_parametersi=iletof_inti=letopenResult_syntaxinifCompare.Int.(i<0||i>max_value)thentzfail(Invalid_sloti)elsereturniletsuccslot=of_int(slot+1)moduleMap=Map.Make(Compare.Int)moduleSet=Set.Make(Compare.Int)moduleRange=struct(* For now, we only need full intervals. If we ever need sparse ones, we
could switch this representation to interval trees. [hi] and [lo] bounds
are included. *)typet=Intervalof{lo:int;hi:int}letcreate~min~count=letopenResult_syntaxinlet*()=error_when(min<0)(Invalid_slotmin)inlet*()=error_when(min>max_value)(Invalid_slotmin)inlet*()=error_when(count<1)(Invalid_slotcount)inlet*()=error_when(count>max_value)(Invalid_slotcount)inletmax=min+count-1inlet*()=error_when(max>max_value)(Invalid_slotmax)inreturn(Interval{lo=min;hi=max})letfoldfinit(Interval{lo;hi})=letrecloop~acc~next=ifCompare.Int.(next>hi)thenaccelseloop~acc:(faccnext)~next:(next+1)inloop~acc:(finitlo)~next:(lo+1)letfold_esfinit(Interval{lo;hi})=letopenLwt_result_syntaxinletrecloop~acc~next=ifCompare.Int.(next>hi)thenreturnaccelselet*acc=faccnextinloop~acc~next:(next+1)inlet*acc=finitloinloop~acc~next:(lo+1)letrev_fold_esfinit(Interval{lo;hi})=letopenLwt_result_syntaxinletrecloop~acc~next=ifCompare.Int.(next<lo)thenreturnaccelselet*acc=faccnextinloop~acc~next:(next-1)inlet*acc=finithiinloop~acc~next:(hi-1)endmoduleInternal_for_tests=structletof_int=of_intend