123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152(* On 32-bit systems, we emulate a 63-bit integer via a boxed 64-bit integer
with its lowest bit set to 0. The remaining 63 bits are left-shifted by one
place. This is analogous to the standard encoding of [int], with the bottom
bit set to 0 rather than 1.
See {{:https://github.com/janestreet/base/blob/master/src/int63_emul.ml}[Base.Int63_emul]}
for a similar encoding that has subtly different guarantees. This
implementation seeks to be strictly observationally equivalent to the
unemulated one (on 64-bit architectures), at the cost of performance of
certain functions.
*)typet=int64(* The following all preserve semantics under our chosen encoding. *)include(Int64:sigvaladd:t->t->tvalsub:t->t->tvalrem:t->t->tvalneg:t->tvalabs:t->tvallogand:t->t->tvallogor:t->t->tvalshift_left:t->int->tvalequal:t->t->boolvalcompare:t->t->intend)letinvalid_argfmt=Format.kasprintfinvalid_argfmtmoduleConv:sigvalwrap_exn:int64->t(* Raises if the [int64] has its topmost bit set. *)valwrap_modulo:int64->t(* Discards the topmost bit of the [int64]. *)valunwrap:t->int64(* Lossless, assuming [t] satisfies the encoding. *)end=structletint64_fits_on_int63=letmin=Int64.(shift_rightmin_int)1inletmax=Int64.(shift_rightmax_int)1infunx->Int64.compareminx<=0&&Int64.comparexmax<=0letwrap_modulox=Int64.mulx2Lletwrap_exnx=ifint64_fits_on_int63xthenInt64.mulx2LelsePrintf.ksprintffailwith"Conversion from int64 to int63 failed: %Ld is out of range"xletunwrapx=Int64.shift_rightx1endletunset_bottom_bit=letmask=0xffff_ffff_ffff_fffELinfunx->Int64.logandxmaskletmin_int=unset_bottom_bitInt64.min_intletmax_int=unset_bottom_bitInt64.max_intletminus_one=Conv.wrap_exn(-1L)letzero=Conv.wrap_exn0Lletone=Conv.wrap_exn1Lletsuccx=addxoneletpredx=subxoneletmulxy=Int64.mulx(Conv.unwrapy)letdivxy=letr=Int64.divxyinifInt64.equalr0x4000_0000_0000_0000Lthen(* This case happens when we overflow via [ min_int / 1 ], in which case we
should wrap back to [ min_int ]. *)min_intelseConv.wrap_modulorletlognotx=unset_bottom_bit(Int64.lognotx)letlogxorxy=unset_bottom_bit(Int64.logxorxy)letshift_rightxi=unset_bottom_bit(Int64.shift_rightxi)letshift_right_logicalxi=unset_bottom_bit(Int64.shift_right_logicalxi)letto_intx=Int64.to_int(Conv.unwrapx)letof_intx=Conv.wrap_exn(Int64.of_intx)letto_int32x=Int64.to_int32(Conv.unwrapx)letof_int32x=Conv.wrap_exn(Int64.of_int32x)letto_int64x=Conv.unwrapxletof_int64x=Conv.wrap_exnxletto_floatx=Int64.to_float(Conv.unwrapx)letof_floatx=Conv.wrap_exn(Int64.of_floatx)letto_stringx=Int64.to_string(Conv.unwrapx)letof_stringx=Conv.wrap_exn(Int64.of_stringx)letof_string_optx=trySome(of_stringx)with_->Noneletppppfx=Format.fprintfppf"%Ld"(Conv.unwrapx)letto_unsigned_intx=letmax_int=of_intStdlib.max_intinifcomparezerox<=0&&comparexmax_int<=0thento_intxelseinvalid_arg"Int63.to_unsigned_int: %Lx can not fit into a 31 bits unsigned integer"xletwithout_bit_sign(x:int)=ifx>=0thenxelsexland(lnot0x40000000)letof_unsigned_intx=ifx<0thenlogor0x40000000L(of_int(without_bit_signx))elseof_intxletto_unsigned_int32x=letmax_int=of_int32Int32.max_intinifcomparezerox<=0&&comparexmax_int<=0thento_int32xelseinvalid_arg"Int63.to_unsigned_int32: %Lx can not fit into a 32 bits unsigned integer"xletof_unsigned_int32x=ifx<0lthenlogor0x80000000L(of_int32(Int32.logandx(Int32.lognot0x80000000l)))elseof_int32xletencoded_size=8externalset_64:bytes->int->int64->unit="%caml_bytes_set64u"externalget_64:string->int->int64="%caml_string_get64"externalswap64:int64->int64="%bswap_int64"letencodebuf~offt=lett=to_int64tinlett=ifnotSys.big_endianthenswap64telsetinset_64bufofftletdecodebuf~off=lett=get_64bufoffinlett=ifnotSys.big_endianthenswap64telsetinof_int64tmoduleInfix=structlet(+)ab=addablet(-)ab=subablet(*)ab=mulablet(%)ab=remablet(/)ab=divablet(land)ab=logandablet(lor)ab=logorablet(lsr)ab=shift_rightablet(lsl)ab=shift_leftablet(&&)=(land)let(||)=(lor)let(>>)=(lsr)let(<<)=(lsl)end